@thunderclap-engine/engine 0.0.0-stage → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (566) hide show
  1. package/CHANGELOG.md +390 -0
  2. package/LICENSE +21 -0
  3. package/README.md +333 -2
  4. package/dist/analytics/analytics.d.ts +80 -0
  5. package/dist/analytics/analytics.js +129 -0
  6. package/dist/analytics/index.d.ts +1 -0
  7. package/dist/analytics/index.js +1 -0
  8. package/dist/anim/aim.d.ts +43 -0
  9. package/dist/anim/aim.js +157 -0
  10. package/dist/anim/clip.d.ts +98 -0
  11. package/dist/anim/clip.js +282 -0
  12. package/dist/anim/compress.d.ts +65 -0
  13. package/dist/anim/compress.js +339 -0
  14. package/dist/anim/foot-ik.d.ts +74 -0
  15. package/dist/anim/foot-ik.js +241 -0
  16. package/dist/anim/graph.d.ts +153 -0
  17. package/dist/anim/graph.js +532 -0
  18. package/dist/anim/ik.d.ts +105 -0
  19. package/dist/anim/ik.js +435 -0
  20. package/dist/anim/index.d.ts +36 -0
  21. package/dist/anim/index.js +21 -0
  22. package/dist/anim/match.d.ts +66 -0
  23. package/dist/anim/match.js +153 -0
  24. package/dist/anim/mixer.d.ts +113 -0
  25. package/dist/anim/mixer.js +314 -0
  26. package/dist/anim/morph.d.ts +41 -0
  27. package/dist/anim/morph.js +94 -0
  28. package/dist/anim/pose.d.ts +74 -0
  29. package/dist/anim/pose.js +254 -0
  30. package/dist/anim/quat.d.ts +44 -0
  31. package/dist/anim/quat.js +187 -0
  32. package/dist/anim/retarget.d.ts +97 -0
  33. package/dist/anim/retarget.js +366 -0
  34. package/dist/anim/root-motion.d.ts +44 -0
  35. package/dist/anim/root-motion.js +224 -0
  36. package/dist/anim/skin-pose.d.ts +39 -0
  37. package/dist/anim/skin-pose.js +53 -0
  38. package/dist/anim/socket.d.ts +47 -0
  39. package/dist/anim/socket.js +84 -0
  40. package/dist/anim/spring-chain.d.ts +73 -0
  41. package/dist/anim/spring-chain.js +294 -0
  42. package/dist/assets/atlas.d.ts +90 -0
  43. package/dist/assets/atlas.js +212 -0
  44. package/dist/assets/baked.d.ts +33 -0
  45. package/dist/assets/baked.js +38 -0
  46. package/dist/assets/bundle.d.ts +88 -0
  47. package/dist/assets/bundle.js +464 -0
  48. package/dist/assets/cache.d.ts +56 -0
  49. package/dist/assets/cache.js +123 -0
  50. package/dist/assets/gltf-load.d.ts +252 -0
  51. package/dist/assets/gltf-load.js +661 -0
  52. package/dist/assets/gltf-skin.d.ts +36 -0
  53. package/dist/assets/gltf-skin.js +109 -0
  54. package/dist/assets/gltf.d.ts +706 -0
  55. package/dist/assets/gltf.js +1376 -0
  56. package/dist/assets/index.d.ts +20 -0
  57. package/dist/assets/index.js +10 -0
  58. package/dist/assets/ktx2.d.ts +71 -0
  59. package/dist/assets/ktx2.js +213 -0
  60. package/dist/assets/manifest.d.ts +79 -0
  61. package/dist/assets/manifest.js +7 -0
  62. package/dist/assets/meshopt.d.ts +23 -0
  63. package/dist/assets/meshopt.js +403 -0
  64. package/dist/audio/audio.d.ts +733 -0
  65. package/dist/audio/audio.js +2013 -0
  66. package/dist/audio/dsp.d.ts +61 -0
  67. package/dist/audio/dsp.js +159 -0
  68. package/dist/audio/duck.d.ts +44 -0
  69. package/dist/audio/duck.js +101 -0
  70. package/dist/audio/envelope.d.ts +53 -0
  71. package/dist/audio/envelope.js +106 -0
  72. package/dist/audio/index.d.ts +13 -0
  73. package/dist/audio/index.js +14 -0
  74. package/dist/audio/music.d.ts +113 -0
  75. package/dist/audio/music.js +548 -0
  76. package/dist/audio/occlusion.d.ts +55 -0
  77. package/dist/audio/occlusion.js +61 -0
  78. package/dist/audio/persist.d.ts +23 -0
  79. package/dist/audio/persist.js +27 -0
  80. package/dist/audio/recipes.d.ts +55 -0
  81. package/dist/audio/recipes.js +227 -0
  82. package/dist/audio/send.d.ts +41 -0
  83. package/dist/audio/send.js +118 -0
  84. package/dist/audio/sprites.d.ts +59 -0
  85. package/dist/audio/sprites.js +43 -0
  86. package/dist/audio/synth.d.ts +103 -0
  87. package/dist/audio/synth.js +197 -0
  88. package/dist/audio/variations.d.ts +25 -0
  89. package/dist/audio/variations.js +55 -0
  90. package/dist/audio/zones.d.ts +100 -0
  91. package/dist/audio/zones.js +167 -0
  92. package/dist/core/detached-surface.d.ts +44 -0
  93. package/dist/core/detached-surface.js +104 -0
  94. package/dist/core/events.d.ts +24 -0
  95. package/dist/core/events.js +43 -0
  96. package/dist/core/game.d.ts +409 -0
  97. package/dist/core/game.js +530 -0
  98. package/dist/core/hash.d.ts +24 -0
  99. package/dist/core/hash.js +49 -0
  100. package/dist/core/index.d.ts +17 -0
  101. package/dist/core/index.js +9 -0
  102. package/dist/core/loop.d.ts +113 -0
  103. package/dist/core/loop.js +185 -0
  104. package/dist/core/math.d.ts +58 -0
  105. package/dist/core/math.js +210 -0
  106. package/dist/core/noise.d.ts +40 -0
  107. package/dist/core/noise.js +247 -0
  108. package/dist/core/pool.d.ts +42 -0
  109. package/dist/core/pool.js +85 -0
  110. package/dist/core/random.d.ts +61 -0
  111. package/dist/core/random.js +199 -0
  112. package/dist/core/scene.d.ts +79 -0
  113. package/dist/core/scene.js +195 -0
  114. package/dist/core/timer.d.ts +66 -0
  115. package/dist/core/timer.js +286 -0
  116. package/dist/fx/billboard-wgsl.d.ts +29 -0
  117. package/dist/fx/billboard-wgsl.js +158 -0
  118. package/dist/fx/billboard.d.ts +249 -0
  119. package/dist/fx/billboard.js +702 -0
  120. package/dist/fx/debug-draw.d.ts +127 -0
  121. package/dist/fx/debug-draw.js +523 -0
  122. package/dist/fx/debug-wgsl.d.ts +7 -0
  123. package/dist/fx/debug-wgsl.js +32 -0
  124. package/dist/fx/decals-wgsl.d.ts +15 -0
  125. package/dist/fx/decals-wgsl.js +173 -0
  126. package/dist/fx/decals.d.ts +216 -0
  127. package/dist/fx/decals.js +607 -0
  128. package/dist/fx/effect.d.ts +129 -0
  129. package/dist/fx/effect.js +349 -0
  130. package/dist/fx/effects/hit-spark.json +48 -0
  131. package/dist/fx/effects/index.d.ts +8 -0
  132. package/dist/fx/effects/index.js +9 -0
  133. package/dist/fx/effects/magic-aura.json +47 -0
  134. package/dist/fx/effects/smoke-puff.json +34 -0
  135. package/dist/fx/emit-surface.d.ts +40 -0
  136. package/dist/fx/emit-surface.js +124 -0
  137. package/dist/fx/flicker.d.ts +30 -0
  138. package/dist/fx/flicker.js +42 -0
  139. package/dist/fx/index.d.ts +31 -0
  140. package/dist/fx/index.js +20 -0
  141. package/dist/fx/particles-wgsl.d.ts +57 -0
  142. package/dist/fx/particles-wgsl.js +828 -0
  143. package/dist/fx/particles.d.ts +566 -0
  144. package/dist/fx/particles.js +1533 -0
  145. package/dist/fx/random.d.ts +15 -0
  146. package/dist/fx/random.js +20 -0
  147. package/dist/fx/sky-wgsl.d.ts +23 -0
  148. package/dist/fx/sky-wgsl.js +127 -0
  149. package/dist/fx/sky.d.ts +96 -0
  150. package/dist/fx/sky.js +175 -0
  151. package/dist/fx/text-atlas.d.ts +143 -0
  152. package/dist/fx/text-atlas.js +327 -0
  153. package/dist/fx/trail-wgsl.d.ts +11 -0
  154. package/dist/fx/trail-wgsl.js +42 -0
  155. package/dist/fx/trail.d.ts +194 -0
  156. package/dist/fx/trail.js +555 -0
  157. package/dist/fx/water-wgsl.d.ts +34 -0
  158. package/dist/fx/water-wgsl.js +197 -0
  159. package/dist/fx/water.d.ts +176 -0
  160. package/dist/fx/water.js +371 -0
  161. package/dist/geom/collide/bvh.d.ts +151 -0
  162. package/dist/geom/collide/bvh.js +493 -0
  163. package/dist/geom/collide/debug.d.ts +14 -0
  164. package/dist/geom/collide/debug.js +74 -0
  165. package/dist/geom/collide/grid.d.ts +26 -0
  166. package/dist/geom/collide/grid.js +91 -0
  167. package/dist/geom/collide/index.d.ts +8 -0
  168. package/dist/geom/collide/index.js +8 -0
  169. package/dist/geom/collide/queries.d.ts +70 -0
  170. package/dist/geom/collide/queries.js +583 -0
  171. package/dist/geom/collide/serialize.d.ts +14 -0
  172. package/dist/geom/collide/serialize.js +145 -0
  173. package/dist/geom/collide/shapes.d.ts +161 -0
  174. package/dist/geom/collide/shapes.js +686 -0
  175. package/dist/geom/collide/slide.d.ts +66 -0
  176. package/dist/geom/collide/slide.js +375 -0
  177. package/dist/geom/collide/tile-slide.d.ts +88 -0
  178. package/dist/geom/collide/tile-slide.js +255 -0
  179. package/dist/geom/geometry.d.ts +95 -0
  180. package/dist/geom/geometry.js +322 -0
  181. package/dist/geom/heightfield.d.ts +72 -0
  182. package/dist/geom/heightfield.js +295 -0
  183. package/dist/geom/hull.d.ts +27 -0
  184. package/dist/geom/hull.js +279 -0
  185. package/dist/geom/index.d.ts +35 -0
  186. package/dist/geom/index.js +23 -0
  187. package/dist/geom/iso.d.ts +74 -0
  188. package/dist/geom/iso.js +89 -0
  189. package/dist/geom/lod.d.ts +29 -0
  190. package/dist/geom/lod.js +27 -0
  191. package/dist/geom/ops.d.ts +47 -0
  192. package/dist/geom/ops.js +285 -0
  193. package/dist/geom/primitives.d.ts +97 -0
  194. package/dist/geom/primitives.js +359 -0
  195. package/dist/geom/shapes.d.ts +43 -0
  196. package/dist/geom/shapes.js +88 -0
  197. package/dist/geom/simplify.d.ts +38 -0
  198. package/dist/geom/simplify.js +519 -0
  199. package/dist/geom/split.d.ts +37 -0
  200. package/dist/geom/split.js +413 -0
  201. package/dist/geom/sweep.d.ts +83 -0
  202. package/dist/geom/sweep.js +534 -0
  203. package/dist/geom/tangents.d.ts +16 -0
  204. package/dist/geom/tangents.js +124 -0
  205. package/dist/geom/triangulate.d.ts +19 -0
  206. package/dist/geom/triangulate.js +147 -0
  207. package/dist/host/default.d.ts +10 -0
  208. package/dist/host/default.js +10 -0
  209. package/dist/host/index.d.ts +4 -0
  210. package/dist/host/index.js +3 -0
  211. package/dist/host/types.d.ts +144 -0
  212. package/dist/host/types.js +1 -0
  213. package/dist/host/web-links.d.ts +38 -0
  214. package/dist/host/web-links.js +110 -0
  215. package/dist/host/web.d.ts +30 -0
  216. package/dist/host/web.js +216 -0
  217. package/dist/host/xr.d.ts +24 -0
  218. package/dist/host/xr.js +59 -0
  219. package/dist/i18n/i18n.d.ts +59 -0
  220. package/dist/i18n/i18n.js +241 -0
  221. package/dist/i18n/index.d.ts +3 -0
  222. package/dist/i18n/index.js +3 -0
  223. package/dist/i18n/message.d.ts +72 -0
  224. package/dist/i18n/message.js +369 -0
  225. package/dist/i18n/negotiate.d.ts +17 -0
  226. package/dist/i18n/negotiate.js +58 -0
  227. package/dist/index.d.ts +7 -0
  228. package/dist/index.js +1 -0
  229. package/dist/input/bindings.d.ts +31 -0
  230. package/dist/input/bindings.js +141 -0
  231. package/dist/input/clock.d.ts +44 -0
  232. package/dist/input/clock.js +49 -0
  233. package/dist/input/follow.d.ts +133 -0
  234. package/dist/input/follow.js +218 -0
  235. package/dist/input/gestures.d.ts +281 -0
  236. package/dist/input/gestures.js +662 -0
  237. package/dist/input/glyphs.d.ts +35 -0
  238. package/dist/input/glyphs.js +216 -0
  239. package/dist/input/gyro.d.ts +85 -0
  240. package/dist/input/gyro.js +140 -0
  241. package/dist/input/index.d.ts +19 -0
  242. package/dist/input/index.js +16 -0
  243. package/dist/input/input.d.ts +543 -0
  244. package/dist/input/input.js +1492 -0
  245. package/dist/input/look.d.ts +327 -0
  246. package/dist/input/look.js +681 -0
  247. package/dist/input/magnify.d.ts +177 -0
  248. package/dist/input/magnify.js +131 -0
  249. package/dist/input/pointer-dispatch.d.ts +138 -0
  250. package/dist/input/pointer-dispatch.js +180 -0
  251. package/dist/input/pointer-router.d.ts +204 -0
  252. package/dist/input/pointer-router.js +533 -0
  253. package/dist/input/pointer-sources.d.ts +164 -0
  254. package/dist/input/pointer-sources.js +306 -0
  255. package/dist/input/rays.d.ts +138 -0
  256. package/dist/input/rays.js +615 -0
  257. package/dist/input/record.d.ts +209 -0
  258. package/dist/input/record.js +601 -0
  259. package/dist/input/touch-zones.d.ts +147 -0
  260. package/dist/input/touch-zones.js +300 -0
  261. package/dist/input/types.d.ts +158 -0
  262. package/dist/input/types.js +1 -0
  263. package/dist/input/xr-source.d.ts +53 -0
  264. package/dist/input/xr-source.js +164 -0
  265. package/dist/nav/astar.d.ts +45 -0
  266. package/dist/nav/astar.js +182 -0
  267. package/dist/nav/corridor.d.ts +40 -0
  268. package/dist/nav/corridor.js +95 -0
  269. package/dist/nav/crowd.d.ts +94 -0
  270. package/dist/nav/crowd.js +624 -0
  271. package/dist/nav/flow.d.ts +61 -0
  272. package/dist/nav/flow.js +193 -0
  273. package/dist/nav/grid.d.ts +108 -0
  274. package/dist/nav/grid.js +210 -0
  275. package/dist/nav/heap.d.ts +22 -0
  276. package/dist/nav/heap.js +92 -0
  277. package/dist/nav/index.d.ts +37 -0
  278. package/dist/nav/index.js +19 -0
  279. package/dist/nav/mesh/areas.d.ts +44 -0
  280. package/dist/nav/mesh/areas.js +98 -0
  281. package/dist/nav/mesh/bake-options.d.ts +33 -0
  282. package/dist/nav/mesh/bake-options.js +76 -0
  283. package/dist/nav/mesh/contour.d.ts +22 -0
  284. package/dist/nav/mesh/contour.js +323 -0
  285. package/dist/nav/mesh/flow3.d.ts +35 -0
  286. package/dist/nav/mesh/flow3.js +229 -0
  287. package/dist/nav/mesh/links.d.ts +38 -0
  288. package/dist/nav/mesh/links.js +72 -0
  289. package/dist/nav/mesh/mesh-path.d.ts +152 -0
  290. package/dist/nav/mesh/mesh-path.js +643 -0
  291. package/dist/nav/mesh/mesh-reach.d.ts +78 -0
  292. package/dist/nav/mesh/mesh-reach.js +450 -0
  293. package/dist/nav/mesh/navmesh.d.ts +117 -0
  294. package/dist/nav/mesh/navmesh.js +647 -0
  295. package/dist/nav/mesh/polymesh.d.ts +24 -0
  296. package/dist/nav/mesh/polymesh.js +384 -0
  297. package/dist/nav/mesh/regions.d.ts +12 -0
  298. package/dist/nav/mesh/regions.js +367 -0
  299. package/dist/nav/mesh/serialize.d.ts +13 -0
  300. package/dist/nav/mesh/serialize.js +197 -0
  301. package/dist/nav/mesh/voxelize.d.ts +111 -0
  302. package/dist/nav/mesh/voxelize.js +552 -0
  303. package/dist/nav/obstacles.d.ts +75 -0
  304. package/dist/nav/obstacles.js +294 -0
  305. package/dist/nav/path.d.ts +59 -0
  306. package/dist/nav/path.js +177 -0
  307. package/dist/nav/query-queue.d.ts +46 -0
  308. package/dist/nav/query-queue.js +308 -0
  309. package/dist/nav/reach.d.ts +53 -0
  310. package/dist/nav/reach.js +148 -0
  311. package/dist/nav/steer.d.ts +36 -0
  312. package/dist/nav/steer.js +78 -0
  313. package/dist/platform/boot.d.ts +28 -0
  314. package/dist/platform/boot.js +43 -0
  315. package/dist/platform/device-mode.d.ts +40 -0
  316. package/dist/platform/device-mode.js +104 -0
  317. package/dist/platform/device.d.ts +31 -0
  318. package/dist/platform/device.js +91 -0
  319. package/dist/platform/environment.d.ts +42 -0
  320. package/dist/platform/environment.js +82 -0
  321. package/dist/platform/gpu.d.ts +40 -0
  322. package/dist/platform/gpu.js +57 -0
  323. package/dist/platform/index.d.ts +18 -0
  324. package/dist/platform/index.js +10 -0
  325. package/dist/platform/letterbox.d.ts +43 -0
  326. package/dist/platform/letterbox.js +57 -0
  327. package/dist/platform/links.d.ts +20 -0
  328. package/dist/platform/links.js +43 -0
  329. package/dist/platform/screens.d.ts +36 -0
  330. package/dist/platform/screens.js +138 -0
  331. package/dist/platform/surface.d.ts +72 -0
  332. package/dist/platform/surface.js +157 -0
  333. package/dist/platform/xr-fake.d.ts +168 -0
  334. package/dist/platform/xr-fake.js +434 -0
  335. package/dist/platform/xr-surface.d.ts +120 -0
  336. package/dist/platform/xr-surface.js +214 -0
  337. package/dist/platform/xr-types.d.ts +262 -0
  338. package/dist/post/ao.d.ts +12 -0
  339. package/dist/post/ao.js +136 -0
  340. package/dist/post/blend.d.ts +27 -0
  341. package/dist/post/blend.js +129 -0
  342. package/dist/post/depth-pass.d.ts +43 -0
  343. package/dist/post/depth-pass.js +118 -0
  344. package/dist/post/dof.d.ts +1 -0
  345. package/dist/post/dof.js +66 -0
  346. package/dist/post/exposure.d.ts +80 -0
  347. package/dist/post/exposure.js +322 -0
  348. package/dist/post/index.d.ts +12 -0
  349. package/dist/post/index.js +11 -0
  350. package/dist/post/lens-dirt.d.ts +13 -0
  351. package/dist/post/lens-dirt.js +91 -0
  352. package/dist/post/lut.d.ts +19 -0
  353. package/dist/post/lut.js +50 -0
  354. package/dist/post/motion-blur.d.ts +9 -0
  355. package/dist/post/motion-blur.js +78 -0
  356. package/dist/post/post-stack.d.ts +302 -0
  357. package/dist/post/post-stack.js +1137 -0
  358. package/dist/post/settings.d.ts +485 -0
  359. package/dist/post/settings.js +416 -0
  360. package/dist/post/shaders.d.ts +25 -0
  361. package/dist/post/shaders.js +410 -0
  362. package/dist/post/ssr.d.ts +16 -0
  363. package/dist/post/ssr.js +155 -0
  364. package/dist/post/taa.d.ts +74 -0
  365. package/dist/post/taa.js +235 -0
  366. package/dist/post/white-balance.d.ts +25 -0
  367. package/dist/post/white-balance.js +98 -0
  368. package/dist/render/bindings.d.ts +98 -0
  369. package/dist/render/bindings.js +281 -0
  370. package/dist/render/blend.d.ts +13 -0
  371. package/dist/render/blend.js +26 -0
  372. package/dist/render/camera-2d.d.ts +72 -0
  373. package/dist/render/camera-2d.js +92 -0
  374. package/dist/render/camera.d.ts +302 -0
  375. package/dist/render/camera.js +671 -0
  376. package/dist/render/color.d.ts +16 -0
  377. package/dist/render/color.js +41 -0
  378. package/dist/render/compressed.d.ts +104 -0
  379. package/dist/render/compressed.js +248 -0
  380. package/dist/render/diagnostics.d.ts +15 -0
  381. package/dist/render/diagnostics.js +43 -0
  382. package/dist/render/dynamic-resolution.d.ts +70 -0
  383. package/dist/render/dynamic-resolution.js +126 -0
  384. package/dist/render/fake-gpu.d.ts +204 -0
  385. package/dist/render/fake-gpu.js +426 -0
  386. package/dist/render/flipbook.d.ts +56 -0
  387. package/dist/render/flipbook.js +87 -0
  388. package/dist/render/frame.d.ts +278 -0
  389. package/dist/render/frame.js +174 -0
  390. package/dist/render/fullscreen.d.ts +54 -0
  391. package/dist/render/fullscreen.js +91 -0
  392. package/dist/render/gpu-timer.d.ts +73 -0
  393. package/dist/render/gpu-timer.js +186 -0
  394. package/dist/render/index.d.ts +53 -0
  395. package/dist/render/index.js +29 -0
  396. package/dist/render/instance-list.d.ts +185 -0
  397. package/dist/render/instance-list.js +547 -0
  398. package/dist/render/lights.d.ts +181 -0
  399. package/dist/render/lights.js +233 -0
  400. package/dist/render/lod.d.ts +54 -0
  401. package/dist/render/lod.js +52 -0
  402. package/dist/render/material.d.ts +165 -0
  403. package/dist/render/material.js +292 -0
  404. package/dist/render/mesh.d.ts +284 -0
  405. package/dist/render/mesh.js +472 -0
  406. package/dist/render/mipmap.d.ts +16 -0
  407. package/dist/render/mipmap.js +121 -0
  408. package/dist/render/parallax.d.ts +50 -0
  409. package/dist/render/parallax.js +47 -0
  410. package/dist/render/pbr-wgsl.d.ts +31 -0
  411. package/dist/render/pbr-wgsl.js +119 -0
  412. package/dist/render/ping-pong.d.ts +42 -0
  413. package/dist/render/ping-pong.js +74 -0
  414. package/dist/render/renderer.d.ts +741 -0
  415. package/dist/render/renderer.js +2486 -0
  416. package/dist/render/scene-pipelines.d.ts +44 -0
  417. package/dist/render/scene-pipelines.js +92 -0
  418. package/dist/render/scene-target.d.ts +170 -0
  419. package/dist/render/scene-target.js +450 -0
  420. package/dist/render/shadow.d.ts +74 -0
  421. package/dist/render/shadow.js +208 -0
  422. package/dist/render/skin.d.ts +112 -0
  423. package/dist/render/skin.js +240 -0
  424. package/dist/render/snapshot.d.ts +36 -0
  425. package/dist/render/snapshot.js +34 -0
  426. package/dist/render/standard.d.ts +162 -0
  427. package/dist/render/standard.js +263 -0
  428. package/dist/render/texture.d.ts +142 -0
  429. package/dist/render/texture.js +228 -0
  430. package/dist/render/tile-layer.d.ts +110 -0
  431. package/dist/render/tile-layer.js +304 -0
  432. package/dist/render/transform.d.ts +115 -0
  433. package/dist/render/transform.js +318 -0
  434. package/dist/render/wgsl.d.ts +131 -0
  435. package/dist/render/wgsl.js +528 -0
  436. package/dist/save/codec.d.ts +49 -0
  437. package/dist/save/codec.js +169 -0
  438. package/dist/save/index.d.ts +8 -0
  439. package/dist/save/index.js +8 -0
  440. package/dist/save/journal.d.ts +24 -0
  441. package/dist/save/journal.js +102 -0
  442. package/dist/save/migrate.d.ts +15 -0
  443. package/dist/save/migrate.js +37 -0
  444. package/dist/save/schema.d.ts +72 -0
  445. package/dist/save/schema.js +154 -0
  446. package/dist/save/settings.d.ts +28 -0
  447. package/dist/save/settings.js +59 -0
  448. package/dist/save/slots.d.ts +56 -0
  449. package/dist/save/slots.js +200 -0
  450. package/dist/save/storage.d.ts +35 -0
  451. package/dist/save/storage.js +62 -0
  452. package/dist/save/store.d.ts +114 -0
  453. package/dist/save/store.js +269 -0
  454. package/dist/testing/fake-host.d.ts +103 -0
  455. package/dist/testing/fake-host.js +163 -0
  456. package/dist/testing/fixed-clock.d.ts +25 -0
  457. package/dist/testing/fixed-clock.js +30 -0
  458. package/dist/testing/index.d.ts +4 -0
  459. package/dist/testing/index.js +5 -0
  460. package/dist/testing/test-game.d.ts +76 -0
  461. package/dist/testing/test-game.js +92 -0
  462. package/dist/tween/ease.d.ts +77 -0
  463. package/dist/tween/ease.js +192 -0
  464. package/dist/tween/index.d.ts +8 -0
  465. package/dist/tween/index.js +7 -0
  466. package/dist/tween/timeline.d.ts +78 -0
  467. package/dist/tween/timeline.js +269 -0
  468. package/dist/tween/tween.d.ts +168 -0
  469. package/dist/tween/tween.js +320 -0
  470. package/dist/ui/anchor.d.ts +206 -0
  471. package/dist/ui/anchor.js +307 -0
  472. package/dist/ui/caption.d.ts +122 -0
  473. package/dist/ui/caption.js +286 -0
  474. package/dist/ui/cursor.d.ts +105 -0
  475. package/dist/ui/cursor.js +261 -0
  476. package/dist/ui/dom.d.ts +30 -0
  477. package/dist/ui/dom.js +92 -0
  478. package/dist/ui/floats.d.ts +86 -0
  479. package/dist/ui/floats.js +260 -0
  480. package/dist/ui/hud.d.ts +198 -0
  481. package/dist/ui/hud.js +431 -0
  482. package/dist/ui/index.d.ts +37 -0
  483. package/dist/ui/index.js +34 -0
  484. package/dist/ui/inventory-card.d.ts +52 -0
  485. package/dist/ui/inventory-card.js +173 -0
  486. package/dist/ui/inventory-context.d.ts +29 -0
  487. package/dist/ui/inventory-context.js +125 -0
  488. package/dist/ui/inventory-drag.d.ts +63 -0
  489. package/dist/ui/inventory-drag.js +394 -0
  490. package/dist/ui/inventory-grid.d.ts +66 -0
  491. package/dist/ui/inventory-grid.js +625 -0
  492. package/dist/ui/inventory-radial.d.ts +39 -0
  493. package/dist/ui/inventory-radial.js +168 -0
  494. package/dist/ui/inventory.d.ts +128 -0
  495. package/dist/ui/inventory.js +154 -0
  496. package/dist/ui/layout.d.ts +356 -0
  497. package/dist/ui/layout.js +856 -0
  498. package/dist/ui/link.d.ts +64 -0
  499. package/dist/ui/link.js +155 -0
  500. package/dist/ui/loading.d.ts +40 -0
  501. package/dist/ui/loading.js +157 -0
  502. package/dist/ui/loupe.d.ts +74 -0
  503. package/dist/ui/loupe.js +164 -0
  504. package/dist/ui/menu-nav.d.ts +33 -0
  505. package/dist/ui/menu-nav.js +28 -0
  506. package/dist/ui/minimap-canvas.d.ts +145 -0
  507. package/dist/ui/minimap-canvas.js +460 -0
  508. package/dist/ui/notify.d.ts +40 -0
  509. package/dist/ui/notify.js +141 -0
  510. package/dist/ui/orb.d.ts +53 -0
  511. package/dist/ui/orb.js +304 -0
  512. package/dist/ui/overlay.d.ts +213 -0
  513. package/dist/ui/overlay.js +394 -0
  514. package/dist/ui/padnav.d.ts +53 -0
  515. package/dist/ui/padnav.js +146 -0
  516. package/dist/ui/perf.d.ts +130 -0
  517. package/dist/ui/perf.js +329 -0
  518. package/dist/ui/rotate-card.d.ts +54 -0
  519. package/dist/ui/rotate-card.js +97 -0
  520. package/dist/ui/stack.d.ts +128 -0
  521. package/dist/ui/stack.js +312 -0
  522. package/dist/ui/styles.d.ts +13 -0
  523. package/dist/ui/styles.js +200 -0
  524. package/dist/ui/text-scale.d.ts +67 -0
  525. package/dist/ui/text-scale.js +102 -0
  526. package/dist/ui/theme.d.ts +70 -0
  527. package/dist/ui/theme.js +98 -0
  528. package/dist/ui/toast.d.ts +23 -0
  529. package/dist/ui/toast.js +46 -0
  530. package/dist/ui/tooltip.d.ts +89 -0
  531. package/dist/ui/tooltip.js +333 -0
  532. package/dist/ui/widgets-2.d.ts +134 -0
  533. package/dist/ui/widgets-2.js +399 -0
  534. package/dist/ui/widgets-3.d.ts +91 -0
  535. package/dist/ui/widgets-3.js +212 -0
  536. package/dist/ui/widgets.d.ts +34 -0
  537. package/dist/ui/widgets.js +50 -0
  538. package/dist/ui/world-panel/index.d.ts +5 -0
  539. package/dist/ui/world-panel/index.js +5 -0
  540. package/dist/ui/world-panel/layout.d.ts +38 -0
  541. package/dist/ui/world-panel/layout.js +68 -0
  542. package/dist/ui/world-panel/paint.d.ts +96 -0
  543. package/dist/ui/world-panel/paint.js +136 -0
  544. package/dist/ui/world-panel/panel.d.ts +235 -0
  545. package/dist/ui/world-panel/panel.js +762 -0
  546. package/dist/ui/world-panel/wgsl.d.ts +10 -0
  547. package/dist/ui/world-panel/wgsl.js +52 -0
  548. package/dist/ui/world-panel/widgets.d.ts +207 -0
  549. package/dist/ui/world-panel/widgets.js +569 -0
  550. package/dist/voxel/chunks.d.ts +77 -0
  551. package/dist/voxel/chunks.js +149 -0
  552. package/dist/voxel/grid.d.ts +84 -0
  553. package/dist/voxel/grid.js +223 -0
  554. package/dist/voxel/index.d.ts +22 -0
  555. package/dist/voxel/index.js +7 -0
  556. package/dist/voxel/mesher-worker.d.ts +14 -0
  557. package/dist/voxel/mesher-worker.js +47 -0
  558. package/dist/voxel/mesher.d.ts +73 -0
  559. package/dist/voxel/mesher.js +306 -0
  560. package/dist/voxel/ray.d.ts +32 -0
  561. package/dist/voxel/ray.js +73 -0
  562. package/dist/voxel/wgsl.d.ts +16 -0
  563. package/dist/voxel/wgsl.js +28 -0
  564. package/dist/voxel/worker-client.d.ts +79 -0
  565. package/dist/voxel/worker-client.js +122 -0
  566. package/package.json +177 -3
@@ -0,0 +1,662 @@
1
+ import { Loupe } from '../ui/loupe.js';
2
+ import { resolveClock } from './clock.js';
3
+ import { loupeClear, loupeSpot, MAGNIFY_DEFAULTS, magnifySize, } from './magnify.js';
4
+ import { createPointerDispatcher, POINTER_PRIORITY, } from './pointer-dispatch.js';
5
+ const DEFAULTS = {
6
+ panThreshold: 10,
7
+ longPressMs: 450,
8
+ doubleTapMs: 300,
9
+ doubleTapDistance: 24,
10
+ };
11
+ /** Most taps (of one kind) queued for later ticks. */
12
+ const MAX_QUEUED = 8;
13
+ /** Fraction of `panThreshold` past which a pointer is a pan candidate. */
14
+ const CANDIDATE_FRACTION = 0.25;
15
+ const CONTINUOUS = ['pan', 'drag', 'pinch'];
16
+ /**
17
+ * Touch and pointer gestures: tap, double tap, long-press, pan, drag and pinch. Feed it pointer
18
+ * events (via `attach` or the public feed methods), call `update()` once per simulation tick,
19
+ * then read this tick's gestures. Thresholds are CSS px; positions are game space through the
20
+ * same `PointerTransform` as `Input`.
21
+ *
22
+ * ```ts
23
+ * const gestures = new Gestures();
24
+ * input.setGestures(gestures); // shares blocked(), the transform, attach and update()
25
+ * // each tick, after input.update():
26
+ * if (gestures.tap) select(gestures.tap.x, gestures.tap.y);
27
+ * if (gestures.drag?.phase === 'move') moveBy(gestures.drag.dx, gestures.drag.dy);
28
+ * ```
29
+ *
30
+ * Or bind them as actions: `{ select: [{ gesture: 'tap' }], info: [{ gesture: 'longPress' }] }`.
31
+ *
32
+ * Rules:
33
+ * - A tap is a down and up that stays within `panThreshold` and ends before `longPressMs`. A
34
+ * double tap also reports a tap for each of its two taps.
35
+ * - A long-press fires once, after `longPressMs` within the threshold; no tap follows it.
36
+ * - Moving past the threshold starts a pan and a drag (one pointer) for the rest of the press.
37
+ * Travel is cumulative from the down point, so a slow drag crosses it too, and the threshold
38
+ * is checked before the long-press timer on every move: a pointer whose travel crosses it
39
+ * never long-presses, however long the frame took. A long-press that already fired stays.
40
+ * - A second pointer cancels the pan and drag (and any tap or long-press) and starts a pinch;
41
+ * while two or more pointers are down, pan and drag report nothing (pinch wins). Lifting
42
+ * either pointer ends the pinch; nothing more is reported until every pointer is up.
43
+ * - Discrete gestures that arrive faster than ticks are queued, one per kind per tick. Moves in
44
+ * one tick are merged; `start` and `end` each get their own tick. While a pan, drag or pinch
45
+ * runs, every tick reports it (a `move` with no change when nothing moved).
46
+ * - While `blocked()` nothing is reported, the press in progress is dropped, and a pan, drag or
47
+ * pinch that had started gets one `cancel`, so the game can put things back.
48
+ */
49
+ export class Gestures {
50
+ /** This tick's gestures, or `null`. */
51
+ tap = null;
52
+ doubleTap = null;
53
+ longPress = null;
54
+ pan = null;
55
+ drag = null;
56
+ pinch = null;
57
+ /** This tick's aim while one touch pointer is down (with the `magnify` option), or `null`. */
58
+ aim = null;
59
+ blocked;
60
+ panThreshold;
61
+ longPressMs;
62
+ doubleTapMs;
63
+ doubleTapDistance;
64
+ /** `GestureOptions.pan`: `'prefer'` keeps a pan candidate from long-pressing. */
65
+ panMode;
66
+ /**
67
+ * The pointer-claim hook (ws/input-3): called on every `pointerDown` with the pointer id and
68
+ * device; when it returns true the pointer is not a gesture (its moves and lift are ignored
69
+ * too). `Input.setLook` installs one so an orbit look drag never pans; a game may install its
70
+ * own when nothing is linked.
71
+ */
72
+ claim = null;
73
+ /**
74
+ * The clock gestures are timed on (`GestureOptions.now`). Recordings stamp pointer events on
75
+ * it and playbacks replay them on it (ws/input-7). `clock.now`, bound.
76
+ */
77
+ now;
78
+ /** The clock (`GestureOptions.clock`, or one wrapping `now`, or the wall clock). */
79
+ clock;
80
+ onPanCandidate;
81
+ transform = null;
82
+ session = null;
83
+ /** Last tap, for double taps: client position and end time. */
84
+ lastTap = null;
85
+ lastInside = { x: 0, y: 0, inside: false };
86
+ /** Taps; `double` marks the second tap of a double tap (reported on the same tick). */
87
+ taps = [];
88
+ longPresses = [];
89
+ pans = [];
90
+ drags = [];
91
+ pinches = [];
92
+ /** Continuous gestures reported as started and not yet ended, with their last report. */
93
+ running = new Map();
94
+ /** The session whose long-press has been reported, while its pointer stays down. */
95
+ longPressSession = null;
96
+ detachFn = null;
97
+ magnify;
98
+ loupe = null;
99
+ /** The aim at the moment the finger lifted, reported (with `ended`) on the next tick. */
100
+ endedAim = null;
101
+ /** `onGesture` listeners, called at recognition time. */
102
+ listeners = [];
103
+ constructor(opts = {}) {
104
+ this.panThreshold = opts.panThreshold ?? DEFAULTS.panThreshold;
105
+ this.longPressMs = opts.longPressMs ?? DEFAULTS.longPressMs;
106
+ this.doubleTapMs = opts.doubleTapMs ?? DEFAULTS.doubleTapMs;
107
+ this.doubleTapDistance = opts.doubleTapDistance ?? DEFAULTS.doubleTapDistance;
108
+ this.blocked = opts.blocked ?? (() => false);
109
+ const c = resolveClock(opts.clock, opts.now);
110
+ this.clock = c.clock;
111
+ this.now = c.now;
112
+ this.magnify = opts.magnify ?? null;
113
+ this.panMode = opts.pan ?? null;
114
+ this.onPanCandidate = opts.onPanCandidate ?? null;
115
+ }
116
+ /** Turn magnify on (or off with `null`) after construction. */
117
+ setMagnify(opts) {
118
+ this.magnify = opts;
119
+ this.aim = null;
120
+ this.loupe?.destroy();
121
+ this.loupe = null;
122
+ }
123
+ /** The loupe element, once one has been shown (for styling and tests). */
124
+ get loupeElement() {
125
+ return this.loupe?.el ?? null;
126
+ }
127
+ /** Install the client → game-space mapping. `null` = identity (relative to the target when attached). */
128
+ setPointerTransform(fn) {
129
+ this.transform = fn;
130
+ this.ownDispatcher?.setTransform(fn);
131
+ }
132
+ // ---------------------------------------------------------------- observer
133
+ /**
134
+ * Observe the gesture stream: `listener` is called synchronously each time a gesture is
135
+ * recognised (a tap on lift, a long-press when its time is up, a pan's `start`, every `move`,
136
+ * `end` or `cancel`), not once per tick. It is an observer for tests, replays and logging; the
137
+ * per-tick fields (`tap`, `drag`, ...) and action bindings stay the way a game reads gestures.
138
+ * Returns the unsubscribe function.
139
+ */
140
+ onGesture(listener) {
141
+ this.listeners.push(listener);
142
+ return () => {
143
+ const i = this.listeners.indexOf(listener);
144
+ if (i >= 0)
145
+ this.listeners.splice(i, 1);
146
+ };
147
+ }
148
+ emit(kind, phase, g) {
149
+ const ls = this.listeners;
150
+ for (let i = 0; i < ls.length; i++)
151
+ ls[i]?.(kind, phase, g);
152
+ }
153
+ // ---------------------------------------------------------------- queries
154
+ /**
155
+ * True while `kind` drives an action binding: on the tick a tap or double tap is reported;
156
+ * from a long-press until its pointer lifts; on a pan, drag or pinch's `start` and `move` ticks.
157
+ */
158
+ active(kind) {
159
+ switch (kind) {
160
+ case 'tap':
161
+ return this.tap !== null;
162
+ case 'doubleTap':
163
+ return this.doubleTap !== null;
164
+ case 'longPress':
165
+ return this.longPress !== null || this.longPressSession !== null;
166
+ default:
167
+ return this.running.has(kind);
168
+ }
169
+ }
170
+ /** True when `kind` was reported fresh this tick: a new tap, double tap, long-press or `start`. */
171
+ fired(kind) {
172
+ switch (kind) {
173
+ case 'tap':
174
+ case 'doubleTap':
175
+ case 'longPress':
176
+ return this[kind] !== null;
177
+ default:
178
+ return this[kind]?.phase === 'start';
179
+ }
180
+ }
181
+ // ---------------------------------------------------------------- tick
182
+ /** Advance one tick: fire due long-presses and publish one report per kind. */
183
+ update() {
184
+ const t = this.now();
185
+ if (this.blocked()) {
186
+ this.clearQueues();
187
+ if (this.session)
188
+ this.session.void = true;
189
+ this.longPressSession = null;
190
+ this.tap = null;
191
+ this.doubleTap = null;
192
+ this.longPress = null;
193
+ // A pan, drag or pinch that had started is cancelled once; nothing else is reported.
194
+ this.lastTap = null;
195
+ this.pan = this.cancelled('pan');
196
+ this.drag = this.cancelled('drag');
197
+ this.pinch = this.cancelled('pinch');
198
+ if (this.pan)
199
+ this.emit('pan', 'cancel', this.pan);
200
+ if (this.drag)
201
+ this.emit('drag', 'cancel', this.drag);
202
+ if (this.pinch)
203
+ this.emit('pinch', 'cancel', this.pinch);
204
+ this.running.clear();
205
+ this.updateAim();
206
+ return;
207
+ }
208
+ this.checkLongPress(t);
209
+ const tap = this.taps.shift();
210
+ this.tap = tap?.tap ?? null;
211
+ this.doubleTap = tap?.double ? tap.tap : null;
212
+ this.longPress = this.longPresses.shift() ?? null;
213
+ if (this.longPress && this.session?.longPressed && !this.session.void) {
214
+ this.longPressSession = this.session;
215
+ }
216
+ this.pan = this.publish('pan', this.pans, mergePan, idlePan);
217
+ this.drag = this.publish('drag', this.drags, mergePan, idlePan);
218
+ this.pinch = this.publish('pinch', this.pinches, mergePinch, idlePinch);
219
+ this.updateAim();
220
+ }
221
+ /**
222
+ * This tick's aim (the `magnify` option): one touch pointer down, not blocked, `when()`. The
223
+ * aim point is the finger, raised by `lift` while it drags; `snap` picks the target; the
224
+ * loupe shows while the pitch is below `below` and the aim is over the targets.
225
+ */
226
+ updateAim() {
227
+ const m = this.magnify;
228
+ const s = this.session;
229
+ const c = s && !s.void && !s.multi ? s.contacts.values().next().value : null;
230
+ // The aim the finger lifted at comes with the drag's `end` (moves before it get their own
231
+ // ticks first, still aiming there).
232
+ let ended = this.endedAim;
233
+ if (ended && this.drags.length > 0)
234
+ ended = { ...ended, ended: false };
235
+ else
236
+ this.endedAim = null;
237
+ const aim = !m || this.blocked() ? null : c ? this.aimOf(m, c, s?.moving === true) : ended;
238
+ this.aim = aim;
239
+ if (!m?.source || !aim?.loupe || aim.ended) {
240
+ this.loupe?.hide();
241
+ return;
242
+ }
243
+ const size = magnifySize(m);
244
+ if (this.loupe && this.loupe.size !== size) {
245
+ this.loupe.destroy();
246
+ this.loupe = null;
247
+ }
248
+ this.loupe ??= new Loupe(m.source, {
249
+ size,
250
+ zoom: m.zoom ?? MAGNIFY_DEFAULTS.zoom,
251
+ className: m.className,
252
+ parent: m.parent,
253
+ });
254
+ let ring = null;
255
+ const t = aim.target;
256
+ if (t) {
257
+ const to = m.toClient ?? ((tx, ty) => ({ x: tx, y: ty }));
258
+ const a = to(t.x, t.y);
259
+ const b = to(t.x + t.r, t.y);
260
+ ring = { x: a.x, y: a.y, r: Math.abs(b.x - a.x) };
261
+ }
262
+ this.loupe.show({ focus: aim.client, at: aim.at, ring, leader: m.leader ? ring : null });
263
+ }
264
+ /** The aim of touch contact `c` (`null` for mouse and pen, or while `when()` is false). */
265
+ aimOf(m, c, lifted) {
266
+ if (c.device !== 'touch' || (m.when && !m.when()))
267
+ return null;
268
+ const lift = lifted ? (m.lift ?? MAGNIFY_DEFAULTS.lift) : 0;
269
+ const finger = { x: c.lastX, y: c.lastY };
270
+ const client = { x: c.lastX, y: c.lastY - lift };
271
+ const p = this.transform ? this.transform(client.x, client.y) : { x: client.x, y: client.y };
272
+ const inside = p !== null;
273
+ const x = p?.x ?? this.lastInside.x;
274
+ const y = p?.y ?? this.lastInside.y;
275
+ const target = inside && m.snap ? m.snap(x, y) : null;
276
+ const over = inside && (m.over ? m.over(x, y) : target !== null);
277
+ const size = magnifySize(m);
278
+ const loupe = over && m.pitch() < (m.below ?? MAGNIFY_DEFAULTS.below);
279
+ const win = (m.source?.ownerDocument ?? globalThis.document)?.defaultView;
280
+ const view = win
281
+ ? { width: win.innerWidth, height: win.innerHeight }
282
+ : { width: Number.POSITIVE_INFINITY, height: Number.POSITIVE_INFINITY };
283
+ const room = loupe && m.clear ? m.clear(target, { x, y }) : null;
284
+ const at = room
285
+ ? loupeClear(finger, client, size, view, room.keep, room.avoid, room.spare)
286
+ : loupeSpot(finger, client, size, view);
287
+ return { x, y, inside, client, finger, lifted, target, loupe, at, ended: false };
288
+ }
289
+ /** The `cancel` report for a running `kind` (blocked), or `null`. */
290
+ cancelled(kind) {
291
+ const last = this.running.get(kind);
292
+ if (!last)
293
+ return null;
294
+ return (kind === 'pinch'
295
+ ? { ...last, phase: 'cancel', delta: 1 }
296
+ : { ...last, phase: 'cancel', dx: 0, dy: 0 });
297
+ }
298
+ /**
299
+ * This tick's report for `kind`: the next queued event (consecutive moves merged), or, while
300
+ * the gesture runs with nothing new, the last report as a `move` with no change.
301
+ */
302
+ publish(kind, queue, merge, idle) {
303
+ let e = queue.shift();
304
+ if (!e) {
305
+ const last = this.running.get(kind);
306
+ return last ? idle(last) : null;
307
+ }
308
+ if (e.phase === 'move') {
309
+ while (queue[0]?.phase === 'move')
310
+ e = merge(e, queue.shift());
311
+ }
312
+ if (e.phase === 'end' || e.phase === 'cancel')
313
+ this.running.delete(kind);
314
+ else
315
+ this.running.set(kind, e);
316
+ return e;
317
+ }
318
+ clearQueues() {
319
+ this.taps.length = 0;
320
+ this.longPresses.length = 0;
321
+ this.pans.length = 0;
322
+ this.drags.length = 0;
323
+ this.pinches.length = 0;
324
+ }
325
+ // ---------------------------------------------------------------- low-level feed
326
+ // Public so tests, replays and automated playtests can drive gestures without a DOM. Positions
327
+ // are client coordinates (CSS px), run through the transform. `time` defaults to the clock.
328
+ pointerDown(id, clientX, clientY, device = 'touch', time = this.now()) {
329
+ if (this.claim?.(id, device))
330
+ return;
331
+ if (!this.session) {
332
+ if (this.blocked())
333
+ return;
334
+ this.session = {
335
+ contacts: new Map(),
336
+ moving: false,
337
+ multi: false,
338
+ void: false,
339
+ longPressed: false,
340
+ pinchStartDist: 0,
341
+ pinchLastDist: 0,
342
+ pinching: false,
343
+ centreLast: null,
344
+ last: null,
345
+ at: null,
346
+ };
347
+ }
348
+ const s = this.session;
349
+ if (s.contacts.has(id))
350
+ return;
351
+ const contact = {
352
+ id,
353
+ device,
354
+ downAt: time,
355
+ startX: clientX,
356
+ startY: clientY,
357
+ lastX: clientX,
358
+ lastY: clientY,
359
+ origin: this.map(clientX, clientY),
360
+ travel: 0,
361
+ candidate: false,
362
+ };
363
+ s.contacts.set(id, contact);
364
+ if (s.void || s.contacts.size !== 2) {
365
+ // A third pointer is ignored; it still has to lift before the session ends.
366
+ return;
367
+ }
368
+ // Second pointer: the press becomes a pinch; a running pan and drag are cancelled, and
369
+ // neither reports again until every pointer is up.
370
+ s.multi = true;
371
+ this.endOnePointer(s, s.contacts.values().next().value, 'cancel');
372
+ const [a, b] = [...s.contacts.values()];
373
+ s.pinchStartDist = Math.max(1, dist(a.lastX, a.lastY, b.lastX, b.lastY));
374
+ s.pinchLastDist = s.pinchStartDist;
375
+ const centre = this.map((a.lastX + b.lastX) / 2, (a.lastY + b.lastY) / 2);
376
+ s.centreLast = centre;
377
+ s.pinching = true;
378
+ this.pushPinch({ phase: 'start', ...centre, scale: 1, delta: 1 });
379
+ }
380
+ pointerMove(id, clientX, clientY, time = this.now()) {
381
+ const s = this.session;
382
+ const c = s?.contacts.get(id);
383
+ if (!s || !c || (clientX === c.lastX && clientY === c.lastY))
384
+ return;
385
+ c.travel += dist(c.lastX, c.lastY, clientX, clientY);
386
+ c.lastX = clientX;
387
+ c.lastY = clientY;
388
+ if (!c.candidate && c.travel > this.panThreshold * CANDIDATE_FRACTION) {
389
+ c.candidate = true;
390
+ this.onPanCandidate?.(id, c.travel);
391
+ }
392
+ if (s.void)
393
+ return;
394
+ if (s.multi) {
395
+ this.moveTwo(s);
396
+ return;
397
+ }
398
+ if (s.longPressed)
399
+ return;
400
+ if (!s.moving) {
401
+ // The threshold first: travel that crosses it is a pan, however late this move arrives
402
+ // (a long frame), and the pending long-press is dropped. Only a still pointer may long-press.
403
+ if (c.travel <= this.panThreshold) {
404
+ this.checkLongPress(time);
405
+ return;
406
+ }
407
+ s.moving = true;
408
+ s.last = c.origin;
409
+ const p = this.map(clientX, clientY);
410
+ this.pushMove(s, c, p, 'start');
411
+ return;
412
+ }
413
+ this.pushMove(s, c, this.map(clientX, clientY), 'move');
414
+ }
415
+ pointerUp(id, clientX, clientY, time = this.now()) {
416
+ const s = this.session;
417
+ const c = s?.contacts.get(id);
418
+ if (!s || !c)
419
+ return;
420
+ if (clientX !== undefined && clientY !== undefined)
421
+ this.pointerMove(id, clientX, clientY, time);
422
+ if (this.magnify && !s.void && !s.multi && !this.blocked()) {
423
+ const aim = this.aimOf(this.magnify, c, s.moving);
424
+ this.endedAim = aim ? { ...aim, ended: true } : null;
425
+ }
426
+ s.contacts.delete(id);
427
+ if (this.longPressSession === s)
428
+ this.longPressSession = null;
429
+ if (!s.void) {
430
+ if (s.multi) {
431
+ this.endTwo(s, 'end');
432
+ s.void = true;
433
+ }
434
+ else if (s.moving) {
435
+ this.endOnePointer(s, c, 'end');
436
+ }
437
+ else if (!s.longPressed) {
438
+ if (time - c.downAt >= this.longPressMs) {
439
+ // Held long enough but no tick saw it (a stalled frame): still a long-press, not a tap.
440
+ // A pan candidate under `pan: 'prefer'` was on its way to a pan: nothing.
441
+ if (!this.preferPan(c))
442
+ this.longPressOf(s, c);
443
+ }
444
+ else {
445
+ this.emitTap(c, time);
446
+ }
447
+ }
448
+ }
449
+ if (s.contacts.size === 0)
450
+ this.session = null;
451
+ }
452
+ /** The browser took the pointer (system gesture, palm rejection): drop the press. */
453
+ pointerCancel(id) {
454
+ const s = this.session;
455
+ if (!s?.contacts.has(id))
456
+ return;
457
+ this.cancelSession(s);
458
+ s.contacts.delete(id);
459
+ if (s.contacts.size === 0)
460
+ this.session = null;
461
+ }
462
+ /** Drop every pointer (focus loss, tab hidden). A started pan, drag or pinch is cancelled. */
463
+ cancelAll() {
464
+ const s = this.session;
465
+ if (s)
466
+ this.cancelSession(s);
467
+ this.session = null;
468
+ this.longPressSession = null;
469
+ }
470
+ cancelSession(s) {
471
+ if (!s.void) {
472
+ if (s.multi)
473
+ this.endTwo(s, 'cancel');
474
+ else
475
+ this.endOnePointer(s, s.contacts.values().next().value, 'cancel');
476
+ }
477
+ s.void = true;
478
+ if (this.longPressSession === s)
479
+ this.longPressSession = null;
480
+ }
481
+ // ---------------------------------------------------------------- recognisers
482
+ checkLongPress(t) {
483
+ const s = this.session;
484
+ if (!s || s.void || s.multi || s.moving || s.longPressed)
485
+ return;
486
+ const c = s.contacts.values().next().value;
487
+ if (!c || t - c.downAt < this.longPressMs || this.preferPan(c))
488
+ return;
489
+ this.longPressOf(s, c);
490
+ }
491
+ /** True when `c` may no longer long-press: a pan candidate under `pan: 'prefer'`. */
492
+ preferPan(c) {
493
+ return this.panMode === 'prefer' && c.candidate;
494
+ }
495
+ longPressOf(s, c) {
496
+ s.longPressed = true;
497
+ const g = { ...c.origin, device: c.device };
498
+ push(this.longPresses, g);
499
+ this.emit('longPress', 'end', g);
500
+ }
501
+ emitTap(c, time) {
502
+ const prev = this.lastTap;
503
+ const double = prev !== null &&
504
+ c.downAt - prev.at <= this.doubleTapMs &&
505
+ dist(prev.x, prev.y, c.startX, c.startY) <= this.doubleTapDistance;
506
+ const tap = { ...c.origin, device: c.device };
507
+ push(this.taps, { tap, double });
508
+ this.lastTap = double ? null : { x: c.startX, y: c.startY, at: time };
509
+ this.emit('tap', 'end', tap);
510
+ if (double)
511
+ this.emit('doubleTap', 'end', tap);
512
+ }
513
+ pushMove(s, c, p, phase) {
514
+ const last = s.last ?? c.origin;
515
+ const dx = p.inside && last.inside ? p.x - last.x : 0;
516
+ const dy = p.inside && last.inside ? p.y - last.y : 0;
517
+ const at = p.inside ? p : { ...last, inside: false };
518
+ s.last = p.inside ? p : last;
519
+ s.at = at;
520
+ this.pushPan(c, phase, at, dx, dy);
521
+ }
522
+ /** Queues one pan and one drag report and tells the listeners. */
523
+ pushPan(c, phase, at, dx, dy) {
524
+ const pan = { phase, ...at, dx, dy, pointers: 1, device: c.device };
525
+ const drag = { phase, ...at, origin: c.origin, dx, dy, device: c.device };
526
+ this.pans.push(pan);
527
+ this.drags.push(drag);
528
+ this.emit('pan', phase, pan);
529
+ this.emit('drag', phase, drag);
530
+ }
531
+ pushPinch(e) {
532
+ push(this.pinches, e);
533
+ this.emit('pinch', e.phase, e);
534
+ }
535
+ /** Ends (or cancels) a one-pointer pan and drag, if one is running in `s`. */
536
+ endOnePointer(s, c, phase) {
537
+ if (!s.moving)
538
+ return;
539
+ s.moving = false;
540
+ this.pushPan(c, phase, s.at ?? c.origin, 0, 0);
541
+ }
542
+ /** Two pointers: only the pinch moves. Their centre moving is not a pan (pinch wins). */
543
+ moveTwo(s) {
544
+ const [a, b] = [...s.contacts.values()];
545
+ const d = Math.max(1, dist(a.lastX, a.lastY, b.lastX, b.lastY));
546
+ const centre = this.map((a.lastX + b.lastX) / 2, (a.lastY + b.lastY) / 2);
547
+ if (centre.inside)
548
+ s.centreLast = centre;
549
+ if (d === s.pinchLastDist)
550
+ return;
551
+ const delta = d / s.pinchLastDist;
552
+ s.pinchLastDist = d;
553
+ const at = centre.inside ? centre : { ...(s.centreLast ?? centre), inside: false };
554
+ this.pushPinch({ phase: 'move', ...at, scale: d / s.pinchStartDist, delta });
555
+ }
556
+ endTwo(s, phase) {
557
+ if (!s.pinching)
558
+ return;
559
+ s.pinching = false;
560
+ const e = {
561
+ phase,
562
+ ...(s.centreLast ?? this.lastInside),
563
+ scale: s.pinchLastDist / s.pinchStartDist,
564
+ delta: 1,
565
+ };
566
+ this.pinches.push(e);
567
+ this.emit('pinch', phase, e);
568
+ }
569
+ map(clientX, clientY) {
570
+ const p = this.transform ? this.transform(clientX, clientY) : { x: clientX, y: clientY };
571
+ if (p) {
572
+ this.lastInside = { x: p.x, y: p.y, inside: true };
573
+ return { x: p.x, y: p.y, inside: true };
574
+ }
575
+ return { x: this.lastInside.x, y: this.lastInside.y, inside: false };
576
+ }
577
+ // ---------------------------------------------------------------- DOM
578
+ /**
579
+ * Listen to pointer events on the target. Mouse: the primary button only. Touch and pen: up
580
+ * to two contacts. The target captures each pointer, so a drag off its edge keeps reporting.
581
+ * `Input.setGestures` calls this from `Input.attach`; call it yourself only when the gestures
582
+ * are used without an `Input`.
583
+ */
584
+ attach(opts) {
585
+ this.detach();
586
+ const target = opts.pointerTarget;
587
+ const prevTouchAction = target.style.touchAction;
588
+ if (opts.disableTouchScroll !== false)
589
+ target.style.touchAction = 'none';
590
+ const shared = opts.dispatcher ?? null;
591
+ const dispatcher = shared ?? createPointerDispatcher(target, { transform: this.transform });
592
+ if (!shared)
593
+ this.ownDispatcher = dispatcher;
594
+ const remove = dispatcher.add(this.consumer, POINTER_PRIORITY.gestures);
595
+ this.detachFn = () => {
596
+ remove();
597
+ if (!shared)
598
+ dispatcher.destroy();
599
+ this.ownDispatcher = null;
600
+ target.style.touchAction = prevTouchAction;
601
+ };
602
+ }
603
+ /** The private dispatcher a standalone `attach` built, or `null` (shared or detached). */
604
+ ownDispatcher = null;
605
+ /**
606
+ * The dispatcher consumer: mouse primary button only; every touch and pen contact. Each event
607
+ * is timed by its `timeStamp` (`eventTime`: `now() - age`), not by when it was handled, so a
608
+ * tap delivered after a stalled frame is still a tap; a replayed event by its recorded time.
609
+ */
610
+ consumer = {
611
+ pointerDown: (p) => {
612
+ if (p.device === 'mouse' && p.button !== 0)
613
+ return;
614
+ this.pointerDown(p.id, p.x, p.y, p.device, this.now() - p.age);
615
+ },
616
+ pointerMove: (p) => this.pointerMove(p.id, p.x, p.y, this.now() - p.age),
617
+ pointerUp: (p) => {
618
+ if (p.device === 'mouse' && p.button !== 0)
619
+ return;
620
+ this.pointerUp(p.id, p.x, p.y, this.now() - p.age);
621
+ },
622
+ pointerCancel: (p) => this.pointerCancel(p.id),
623
+ cancelAll: () => this.cancelAll(),
624
+ };
625
+ detach() {
626
+ this.detachFn?.();
627
+ this.detachFn = null;
628
+ this.cancelAll();
629
+ this.aim = null;
630
+ this.endedAim = null;
631
+ this.loupe?.hide();
632
+ }
633
+ /** Detach and remove the loupe element. */
634
+ destroy() {
635
+ this.detach();
636
+ this.loupe?.destroy();
637
+ this.loupe = null;
638
+ }
639
+ }
640
+ function dist(ax, ay, bx, by) {
641
+ return Math.hypot(bx - ax, by - ay);
642
+ }
643
+ function push(queue, e) {
644
+ if (queue.length < MAX_QUEUED)
645
+ queue.push(e);
646
+ }
647
+ function idlePan(last) {
648
+ return { ...last, phase: 'move', dx: 0, dy: 0 };
649
+ }
650
+ function idlePinch(last) {
651
+ return { ...last, phase: 'move', delta: 1 };
652
+ }
653
+ function mergePan(a, b) {
654
+ return { ...b, dx: a.dx + b.dx, dy: a.dy + b.dy };
655
+ }
656
+ function mergePinch(a, b) {
657
+ return { ...b, delta: a.delta * b.delta };
658
+ }
659
+ /** `new Gestures(opts)`: gestures, on `opts.clock` when given (ws/input-8). */
660
+ export function createGestures(opts = {}) {
661
+ return new Gestures(opts);
662
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Prompt glyphs (ws/input-3): the label a game shows for a binding ("Space", "A", "Cross", "Tap"),
3
+ * chosen for the device the player last used. Pure tables, no DOM; `Input.glyphFor(action,
4
+ * device?)` picks the binding and calls `glyphForBinding`. The engine draws nothing: `kind` says
5
+ * which icon set a game's UI should reach for, `label` is the text.
6
+ */
7
+ import type { Binding, InputDevice } from './types.js';
8
+ /** What a glyph stands for. */
9
+ export type GlyphKind = 'key' | 'button' | 'axis' | 'pointer' | 'gesture' | 'xr';
10
+ /** A prompt glyph: `kind` picks the icon set, `label` is the text. */
11
+ export interface Glyph {
12
+ kind: GlyphKind;
13
+ label: string;
14
+ }
15
+ /** Button naming families. `guessPadLayout(gamepad.id)` picks one; `InputOptions.padLayout` overrides. */
16
+ export type PadLayout = 'xbox' | 'playstation' | 'nintendo' | 'generic';
17
+ /** The pad layout for a `Gamepad.id` (vendor words and USB vendor ids), `'generic'` when unknown. */
18
+ export declare function guessPadLayout(id: string | undefined): PadLayout;
19
+ /** Standard-mapping pad button `index` in `layout` (`'Button 7'` past the table or for `'generic'`). */
20
+ export declare function padButtonLabel(index: number, layout?: PadLayout): string;
21
+ /** Standard-mapping pad axis `axis` pushed in `dir`: `'LS →'`, `'RS ↑'`, or `'Axis 4 +'` past the sticks. */
22
+ export declare function padAxisLabel(axis: number, dir: 1 | -1): string;
23
+ /**
24
+ * Display text for a `KeyboardEvent.code`: `'KeyA'` → `'A'`, `'Digit1'` → `'1'`, `'Numpad1'` →
25
+ * `'Num 1'`, `'F5'` → `'F5'`, arrows as arrows, modifiers without their side; unknown codes are
26
+ * split at their capitals (`'AudioVolumeUp'` → `'Audio Volume Up'`).
27
+ */
28
+ export declare function keyLabel(code: string): string;
29
+ /**
30
+ * The glyph for one binding. A chord joins its members with ` + ` and takes the first member's
31
+ * kind; `trigger: 'hold'` prefixes `Hold `, `'doubleTap'` prefixes `Double-tap `.
32
+ */
33
+ export declare function glyphForBinding(b: Binding, layout?: PadLayout): Glyph;
34
+ /** True when `b` is what `device` produces, so its glyph is the one to show for that device. */
35
+ export declare function bindingMatchesDevice(b: Binding, device: InputDevice): boolean;