@driftengine/core 3.61.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 (955) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +9 -0
  3. package/README.md +9 -0
  4. package/dist/behavior/behaviorTree.d.ts +140 -0
  5. package/dist/behavior/behaviorTree.js +289 -0
  6. package/dist/build/shaderComments.d.ts +64 -0
  7. package/dist/build/shaderComments.js +0 -0
  8. package/dist/cinematic/player.d.ts +80 -0
  9. package/dist/cinematic/player.js +184 -0
  10. package/dist/cinematic/script.d.ts +63 -0
  11. package/dist/cinematic/script.js +141 -0
  12. package/dist/core/bootGate.d.ts +37 -0
  13. package/dist/core/bootGate.js +47 -0
  14. package/dist/core/loadTracker.d.ts +78 -0
  15. package/dist/core/loadTracker.js +106 -0
  16. package/dist/core/loop.d.ts +118 -0
  17. package/dist/core/loop.js +84 -0
  18. package/dist/core/messageQueue.d.ts +61 -0
  19. package/dist/core/messageQueue.js +104 -0
  20. package/dist/core/onceSet.d.ts +27 -0
  21. package/dist/core/onceSet.js +62 -0
  22. package/dist/core/preferences.d.ts +47 -0
  23. package/dist/core/preferences.js +140 -0
  24. package/dist/core/remoteSave.d.ts +154 -0
  25. package/dist/core/remoteSave.js +249 -0
  26. package/dist/core/rng.d.ts +64 -0
  27. package/dist/core/rng.js +72 -0
  28. package/dist/core/stepBudget.d.ts +91 -0
  29. package/dist/core/stepBudget.js +105 -0
  30. package/dist/core/storage.d.ts +52 -0
  31. package/dist/core/storage.js +85 -0
  32. package/dist/core/tickTrace.d.ts +72 -0
  33. package/dist/core/tickTrace.js +102 -0
  34. package/dist/core/timeCurve.d.ts +83 -0
  35. package/dist/core/timeCurve.js +107 -0
  36. package/dist/core/withDefaults.d.ts +21 -0
  37. package/dist/core/withDefaults.js +29 -0
  38. package/dist/dev/contactProbe.d.ts +41 -0
  39. package/dist/dev/contactProbe.js +58 -0
  40. package/dist/dev/fpsMeter.d.ts +45 -0
  41. package/dist/dev/fpsMeter.js +86 -0
  42. package/dist/environment/celestialClock.d.ts +141 -0
  43. package/dist/environment/celestialClock.js +262 -0
  44. package/dist/geometry/decal.d.ts +61 -0
  45. package/dist/geometry/decal.js +178 -0
  46. package/dist/geometry/filmPatch.d.ts +35 -0
  47. package/dist/geometry/filmPatch.js +112 -0
  48. package/dist/geometry/growable.d.ts +70 -0
  49. package/dist/geometry/growable.js +167 -0
  50. package/dist/geometry/lightVolume.d.ts +76 -0
  51. package/dist/geometry/lightVolume.js +65 -0
  52. package/dist/geometry/meshBuilder.d.ts +426 -0
  53. package/dist/geometry/meshBuilder.js +1184 -0
  54. package/dist/geometry/pixelFont.d.ts +59 -0
  55. package/dist/geometry/pixelFont.js +179 -0
  56. package/dist/geometry/ribbon.d.ts +101 -0
  57. package/dist/geometry/ribbon.js +546 -0
  58. package/dist/geometry/shellFill.d.ts +101 -0
  59. package/dist/geometry/shellFill.js +203 -0
  60. package/dist/geometry/spline.d.ts +162 -0
  61. package/dist/geometry/spline.js +527 -0
  62. package/dist/geometry/tangents.d.ts +30 -0
  63. package/dist/geometry/tangents.js +142 -0
  64. package/dist/geometry/textMesh.d.ts +51 -0
  65. package/dist/geometry/textMesh.js +57 -0
  66. package/dist/geometry/treeBuilder.d.ts +37 -0
  67. package/dist/geometry/treeBuilder.js +56 -0
  68. package/dist/host/display.d.ts +135 -0
  69. package/dist/host/display.js +114 -0
  70. package/dist/host/files.d.ts +25 -0
  71. package/dist/host/files.js +44 -0
  72. package/dist/host/lifecycle.d.ts +45 -0
  73. package/dist/host/lifecycle.js +28 -0
  74. package/dist/host/platformServices.d.ts +23 -0
  75. package/dist/host/platformServices.js +1 -0
  76. package/dist/host/screen.d.ts +49 -0
  77. package/dist/host/screen.js +90 -0
  78. package/dist/index.d.ts +289 -0
  79. package/dist/index.js +320 -0
  80. package/dist/input/actionMap.d.ts +181 -0
  81. package/dist/input/actionMap.js +314 -0
  82. package/dist/input/activeDevice.d.ts +55 -0
  83. package/dist/input/activeDevice.js +83 -0
  84. package/dist/input/gamepadIdentity.d.ts +43 -0
  85. package/dist/input/gamepadIdentity.js +108 -0
  86. package/dist/input/gamepadMapping.d.ts +56 -0
  87. package/dist/input/gamepadMapping.js +91 -0
  88. package/dist/input/input.d.ts +281 -0
  89. package/dist/input/input.js +703 -0
  90. package/dist/input/inputHarness.d.ts +42 -0
  91. package/dist/input/inputHarness.js +193 -0
  92. package/dist/input/rightGesture.d.ts +57 -0
  93. package/dist/input/rightGesture.js +49 -0
  94. package/dist/input/rumble.d.ts +71 -0
  95. package/dist/input/rumble.js +119 -0
  96. package/dist/input/touchControls.d.ts +138 -0
  97. package/dist/input/touchControls.js +352 -0
  98. package/dist/input/typingTarget.d.ts +6 -0
  99. package/dist/input/typingTarget.js +27 -0
  100. package/dist/math/bounds.d.ts +61 -0
  101. package/dist/math/bounds.js +121 -0
  102. package/dist/math/color.d.ts +8 -0
  103. package/dist/math/color.js +35 -0
  104. package/dist/math/exact.d.ts +66 -0
  105. package/dist/math/exact.js +262 -0
  106. package/dist/math/frustum.d.ts +44 -0
  107. package/dist/math/frustum.js +90 -0
  108. package/dist/math/intersect.d.ts +76 -0
  109. package/dist/math/intersect.js +185 -0
  110. package/dist/math/scalar.d.ts +51 -0
  111. package/dist/math/scalar.js +99 -0
  112. package/dist/math/spring.d.ts +59 -0
  113. package/dist/math/spring.js +88 -0
  114. package/dist/nav/navGraph.d.ts +71 -0
  115. package/dist/nav/navGraph.js +111 -0
  116. package/dist/nav/navPath.d.ts +93 -0
  117. package/dist/nav/navPath.js +162 -0
  118. package/dist/nav/navSearch.d.ts +74 -0
  119. package/dist/nav/navSearch.js +198 -0
  120. package/dist/physics/boxSurface.d.ts +48 -0
  121. package/dist/physics/boxSurface.js +73 -0
  122. package/dist/physics/colliderSurface.d.ts +46 -0
  123. package/dist/physics/colliderSurface.js +146 -0
  124. package/dist/physics/compositeSurface.d.ts +33 -0
  125. package/dist/physics/compositeSurface.js +108 -0
  126. package/dist/physics/heightSurface.d.ts +103 -0
  127. package/dist/physics/heightSurface.js +153 -0
  128. package/dist/physics/ribbonSurface.d.ts +239 -0
  129. package/dist/physics/ribbonSurface.js +522 -0
  130. package/dist/render/ambientOcclusionPass.d.ts +53 -0
  131. package/dist/render/ambientOcclusionPass.js +179 -0
  132. package/dist/render/areaLights.d.ts +116 -0
  133. package/dist/render/areaLights.js +91 -0
  134. package/dist/render/areaShadowSet.d.ts +184 -0
  135. package/dist/render/areaShadowSet.js +277 -0
  136. package/dist/render/atmosphere.d.ts +94 -0
  137. package/dist/render/atmosphere.js +91 -0
  138. package/dist/render/backend/api.d.ts +496 -0
  139. package/dist/render/backend/api.js +1 -0
  140. package/dist/render/backend/budget.d.ts +82 -0
  141. package/dist/render/backend/budget.js +99 -0
  142. package/dist/render/backend/createRenderer.d.ts +135 -0
  143. package/dist/render/backend/createRenderer.js +201 -0
  144. package/dist/render/backend/deadline.d.ts +24 -0
  145. package/dist/render/backend/deadline.js +38 -0
  146. package/dist/render/backend/probe.d.ts +30 -0
  147. package/dist/render/backend/probe.js +129 -0
  148. package/dist/render/backend/select.d.ts +70 -0
  149. package/dist/render/backend/select.js +249 -0
  150. package/dist/render/backend/timer.d.ts +50 -0
  151. package/dist/render/backend/timer.js +1 -0
  152. package/dist/render/backend/webgl2/instanced.d.ts +21 -0
  153. package/dist/render/backend/webgl2/instanced.js +42 -0
  154. package/dist/render/backend/webgl2/morphTexture.d.ts +21 -0
  155. package/dist/render/backend/webgl2/morphTexture.js +55 -0
  156. package/dist/render/backend/webgl2/renderer.d.ts +3027 -0
  157. package/dist/render/backend/webgl2/renderer.js +6041 -0
  158. package/dist/render/backend/webgl2/skinPaletteTexture.d.ts +32 -0
  159. package/dist/render/backend/webgl2/skinPaletteTexture.js +68 -0
  160. package/dist/render/backend/webgpu/boltPass.d.ts +42 -0
  161. package/dist/render/backend/webgpu/boltPass.js +160 -0
  162. package/dist/render/backend/webgpu/buffers.d.ts +159 -0
  163. package/dist/render/backend/webgpu/buffers.js +402 -0
  164. package/dist/render/backend/webgpu/causticsPass.d.ts +36 -0
  165. package/dist/render/backend/webgpu/causticsPass.js +138 -0
  166. package/dist/render/backend/webgpu/clusterBinner.d.ts +51 -0
  167. package/dist/render/backend/webgpu/clusterBinner.js +206 -0
  168. package/dist/render/backend/webgpu/depthPass.d.ts +114 -0
  169. package/dist/render/backend/webgpu/depthPass.js +228 -0
  170. package/dist/render/backend/webgpu/device.d.ts +52 -0
  171. package/dist/render/backend/webgpu/device.js +121 -0
  172. package/dist/render/backend/webgpu/drawCommand.d.ts +43 -0
  173. package/dist/render/backend/webgpu/drawCommand.js +54 -0
  174. package/dist/render/backend/webgpu/environmentTexels.d.ts +28 -0
  175. package/dist/render/backend/webgpu/environmentTexels.js +79 -0
  176. package/dist/render/backend/webgpu/filmPass.d.ts +29 -0
  177. package/dist/render/backend/webgpu/filmPass.js +97 -0
  178. package/dist/render/backend/webgpu/flatPass.d.ts +213 -0
  179. package/dist/render/backend/webgpu/flatPass.js +482 -0
  180. package/dist/render/backend/webgpu/flockPass.d.ts +34 -0
  181. package/dist/render/backend/webgpu/flockPass.js +129 -0
  182. package/dist/render/backend/webgpu/gpuTimestamps.d.ts +94 -0
  183. package/dist/render/backend/webgpu/gpuTimestamps.js +213 -0
  184. package/dist/render/backend/webgpu/insetPass.d.ts +19 -0
  185. package/dist/render/backend/webgpu/insetPass.js +108 -0
  186. package/dist/render/backend/webgpu/instanced.d.ts +27 -0
  187. package/dist/render/backend/webgpu/instanced.js +49 -0
  188. package/dist/render/backend/webgpu/lightVolumePass.d.ts +75 -0
  189. package/dist/render/backend/webgpu/lightVolumePass.js +154 -0
  190. package/dist/render/backend/webgpu/linePass.d.ts +90 -0
  191. package/dist/render/backend/webgpu/linePass.js +220 -0
  192. package/dist/render/backend/webgpu/morphTexture.d.ts +18 -0
  193. package/dist/render/backend/webgpu/morphTexture.js +51 -0
  194. package/dist/render/backend/webgpu/panelPass.d.ts +37 -0
  195. package/dist/render/backend/webgpu/panelPass.js +114 -0
  196. package/dist/render/backend/webgpu/particlePass.d.ts +89 -0
  197. package/dist/render/backend/webgpu/particlePass.js +280 -0
  198. package/dist/render/backend/webgpu/pipelineCache.d.ts +93 -0
  199. package/dist/render/backend/webgpu/pipelineCache.js +140 -0
  200. package/dist/render/backend/webgpu/plumePass.d.ts +69 -0
  201. package/dist/render/backend/webgpu/plumePass.js +213 -0
  202. package/dist/render/backend/webgpu/pointShadowPass.d.ts +88 -0
  203. package/dist/render/backend/webgpu/pointShadowPass.js +280 -0
  204. package/dist/render/backend/webgpu/postPass.d.ts +342 -0
  205. package/dist/render/backend/webgpu/postPass.js +366 -0
  206. package/dist/render/backend/webgpu/probePass.d.ts +108 -0
  207. package/dist/render/backend/webgpu/probePass.js +188 -0
  208. package/dist/render/backend/webgpu/reflectionPass.d.ts +29 -0
  209. package/dist/render/backend/webgpu/reflectionPass.js +87 -0
  210. package/dist/render/backend/webgpu/renderer.d.ts +3082 -0
  211. package/dist/render/backend/webgpu/renderer.js +10911 -0
  212. package/dist/render/backend/webgpu/scatterPass.d.ts +95 -0
  213. package/dist/render/backend/webgpu/scatterPass.js +266 -0
  214. package/dist/render/backend/webgpu/sdfTextPass.d.ts +86 -0
  215. package/dist/render/backend/webgpu/sdfTextPass.js +190 -0
  216. package/dist/render/backend/webgpu/shaderModules.d.ts +9 -0
  217. package/dist/render/backend/webgpu/shaderModules.js +45 -0
  218. package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.d.ts +23 -0
  219. package/dist/render/backend/webgpu/shaders/clusterBin.wgsl.js +208 -0
  220. package/dist/render/backend/webgpu/skinPaletteRing.d.ts +67 -0
  221. package/dist/render/backend/webgpu/skinPaletteRing.js +97 -0
  222. package/dist/render/backend/webgpu/skinPaletteTexture.d.ts +17 -0
  223. package/dist/render/backend/webgpu/skinPaletteTexture.js +68 -0
  224. package/dist/render/backend/webgpu/skyPass.d.ts +102 -0
  225. package/dist/render/backend/webgpu/skyPass.js +70 -0
  226. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +41 -0
  227. package/dist/render/backend/webgpu/surfaceTexturePass.js +228 -0
  228. package/dist/render/backend/webgpu/textPass.d.ts +73 -0
  229. package/dist/render/backend/webgpu/textPass.js +190 -0
  230. package/dist/render/backend/webgpu/uniformRing.d.ts +133 -0
  231. package/dist/render/backend/webgpu/uniformRing.js +208 -0
  232. package/dist/render/backend/webgpu/waterPass.d.ts +73 -0
  233. package/dist/render/backend/webgpu/waterPass.js +160 -0
  234. package/dist/render/backend/webgpu/windStreakPass.d.ts +46 -0
  235. package/dist/render/backend/webgpu/windStreakPass.js +153 -0
  236. package/dist/render/billboard.d.ts +27 -0
  237. package/dist/render/billboard.js +79 -0
  238. package/dist/render/bloomChain.d.ts +66 -0
  239. package/dist/render/bloomChain.js +83 -0
  240. package/dist/render/bloomPass.d.ts +54 -0
  241. package/dist/render/bloomPass.js +219 -0
  242. package/dist/render/boltBatch.d.ts +39 -0
  243. package/dist/render/boltBatch.js +121 -0
  244. package/dist/render/boltPool.d.ts +135 -0
  245. package/dist/render/boltPool.js +259 -0
  246. package/dist/render/boom.d.ts +46 -0
  247. package/dist/render/boom.js +81 -0
  248. package/dist/render/camera.d.ts +119 -0
  249. package/dist/render/camera.js +304 -0
  250. package/dist/render/causticsRenderer.d.ts +63 -0
  251. package/dist/render/causticsRenderer.js +119 -0
  252. package/dist/render/cinematicCamera.d.ts +102 -0
  253. package/dist/render/cinematicCamera.js +227 -0
  254. package/dist/render/clusteredLights.d.ts +260 -0
  255. package/dist/render/clusteredLights.js +479 -0
  256. package/dist/render/colourGrade.d.ts +62 -0
  257. package/dist/render/colourGrade.js +91 -0
  258. package/dist/render/compute.d.ts +74 -0
  259. package/dist/render/compute.js +8 -0
  260. package/dist/render/contextLoss.d.ts +32 -0
  261. package/dist/render/contextLoss.js +46 -0
  262. package/dist/render/debugLines.d.ts +75 -0
  263. package/dist/render/debugLines.js +281 -0
  264. package/dist/render/decalPass.d.ts +34 -0
  265. package/dist/render/decalPass.js +103 -0
  266. package/dist/render/decalProjector.d.ts +140 -0
  267. package/dist/render/decalProjector.js +282 -0
  268. package/dist/render/decalQueue.d.ts +53 -0
  269. package/dist/render/decalQueue.js +87 -0
  270. package/dist/render/depthConvention.d.ts +314 -0
  271. package/dist/render/depthConvention.js +346 -0
  272. package/dist/render/drawingBuffer.d.ts +52 -0
  273. package/dist/render/drawingBuffer.js +67 -0
  274. package/dist/render/emptyTexture.d.ts +60 -0
  275. package/dist/render/emptyTexture.js +103 -0
  276. package/dist/render/envProbeArray.d.ts +85 -0
  277. package/dist/render/envProbeArray.js +164 -0
  278. package/dist/render/equirectToCube.d.ts +54 -0
  279. package/dist/render/equirectToCube.js +123 -0
  280. package/dist/render/flockGeometry.d.ts +23 -0
  281. package/dist/render/flockGeometry.js +43 -0
  282. package/dist/render/flockRenderer.d.ts +37 -0
  283. package/dist/render/flockRenderer.js +70 -0
  284. package/dist/render/frame/arena.d.ts +32 -0
  285. package/dist/render/frame/arena.js +65 -0
  286. package/dist/render/frame/index.d.ts +18 -0
  287. package/dist/render/frame/index.js +4 -0
  288. package/dist/render/frame/replay.d.ts +34 -0
  289. package/dist/render/frame/replay.js +48 -0
  290. package/dist/render/frame/resources.d.ts +25 -0
  291. package/dist/render/frame/resources.js +55 -0
  292. package/dist/render/frame/schedule.d.ts +37 -0
  293. package/dist/render/frame/schedule.js +61 -0
  294. package/dist/render/frameView.d.ts +19 -0
  295. package/dist/render/frameView.js +1 -0
  296. package/dist/render/gizmo.d.ts +236 -0
  297. package/dist/render/gizmo.js +727 -0
  298. package/dist/render/globalMedium.d.ts +124 -0
  299. package/dist/render/globalMedium.js +100 -0
  300. package/dist/render/globalMediumPass.d.ts +101 -0
  301. package/dist/render/globalMediumPass.js +250 -0
  302. package/dist/render/gpuCapability.d.ts +111 -0
  303. package/dist/render/gpuCapability.js +194 -0
  304. package/dist/render/gpuTimer.d.ts +87 -0
  305. package/dist/render/gpuTimer.js +145 -0
  306. package/dist/render/halfFloat.d.ts +4 -0
  307. package/dist/render/halfFloat.js +38 -0
  308. package/dist/render/handleRegistry.d.ts +54 -0
  309. package/dist/render/handleRegistry.js +84 -0
  310. package/dist/render/iesProfile.d.ts +64 -0
  311. package/dist/render/iesProfile.js +179 -0
  312. package/dist/render/imageTexels.d.ts +50 -0
  313. package/dist/render/imageTexels.js +91 -0
  314. package/dist/render/instancedMesh.d.ts +48 -0
  315. package/dist/render/instancedMesh.js +127 -0
  316. package/dist/render/instances.d.ts +69 -0
  317. package/dist/render/instances.js +52 -0
  318. package/dist/render/lightBudget.d.ts +397 -0
  319. package/dist/render/lightBudget.js +524 -0
  320. package/dist/render/lightMatrix.d.ts +3 -0
  321. package/dist/render/lightMatrix.js +45 -0
  322. package/dist/render/lightVolumeDraw.d.ts +132 -0
  323. package/dist/render/lightVolumeDraw.js +181 -0
  324. package/dist/render/lineBatch.d.ts +60 -0
  325. package/dist/render/lineBatch.js +160 -0
  326. package/dist/render/linePoints.d.ts +33 -0
  327. package/dist/render/linePoints.js +46 -0
  328. package/dist/render/livePointShadowSet.d.ts +72 -0
  329. package/dist/render/livePointShadowSet.js +258 -0
  330. package/dist/render/lod.d.ts +35 -0
  331. package/dist/render/lod.js +65 -0
  332. package/dist/render/mesh.d.ts +177 -0
  333. package/dist/render/mesh.js +466 -0
  334. package/dist/render/occlusion.d.ts +81 -0
  335. package/dist/render/occlusion.js +378 -0
  336. package/dist/render/oitPass.d.ts +67 -0
  337. package/dist/render/oitPass.js +213 -0
  338. package/dist/render/orderIndependent.d.ts +92 -0
  339. package/dist/render/orderIndependent.js +108 -0
  340. package/dist/render/particleBatch.d.ts +140 -0
  341. package/dist/render/particleBatch.js +186 -0
  342. package/dist/render/particleMaterial.d.ts +54 -0
  343. package/dist/render/particleMaterial.js +42 -0
  344. package/dist/render/particlePool.d.ts +124 -0
  345. package/dist/render/particlePool.js +182 -0
  346. package/dist/render/pass.d.ts +195 -0
  347. package/dist/render/pass.js +9 -0
  348. package/dist/render/passTarget.d.ts +86 -0
  349. package/dist/render/passTarget.js +121 -0
  350. package/dist/render/pickable.d.ts +31 -0
  351. package/dist/render/pickable.js +172 -0
  352. package/dist/render/planarReflection.d.ts +59 -0
  353. package/dist/render/planarReflection.js +194 -0
  354. package/dist/render/planarReflectionDraw.d.ts +31 -0
  355. package/dist/render/planarReflectionDraw.js +65 -0
  356. package/dist/render/plumeGeometry.d.ts +25 -0
  357. package/dist/render/plumeGeometry.js +61 -0
  358. package/dist/render/plumeMaterial.d.ts +31 -0
  359. package/dist/render/plumeMaterial.js +64 -0
  360. package/dist/render/plumeRenderer.d.ts +96 -0
  361. package/dist/render/plumeRenderer.js +185 -0
  362. package/dist/render/pointLightSelection.d.ts +175 -0
  363. package/dist/render/pointLightSelection.js +301 -0
  364. package/dist/render/pointShadowArray.d.ts +95 -0
  365. package/dist/render/pointShadowArray.js +219 -0
  366. package/dist/render/pointShadowBudget.d.ts +118 -0
  367. package/dist/render/pointShadowBudget.js +221 -0
  368. package/dist/render/pointShadowImage.d.ts +265 -0
  369. package/dist/render/pointShadowImage.js +339 -0
  370. package/dist/render/pointShadowMap.d.ts +93 -0
  371. package/dist/render/pointShadowMap.js +167 -0
  372. package/dist/render/pointShadowSystem.d.ts +195 -0
  373. package/dist/render/pointShadowSystem.js +336 -0
  374. package/dist/render/prefilterEnvMap.d.ts +124 -0
  375. package/dist/render/prefilterEnvMap.js +146 -0
  376. package/dist/render/prefilterPass.d.ts +44 -0
  377. package/dist/render/prefilterPass.js +98 -0
  378. package/dist/render/probeGrid.d.ts +122 -0
  379. package/dist/render/probeGrid.js +174 -0
  380. package/dist/render/rainField.d.ts +99 -0
  381. package/dist/render/rainField.js +168 -0
  382. package/dist/render/reflectionProbe.d.ts +188 -0
  383. package/dist/render/reflectionProbe.js +437 -0
  384. package/dist/render/renderQuality.d.ts +699 -0
  385. package/dist/render/renderQuality.js +293 -0
  386. package/dist/render/rendererHarness.d.ts +39 -0
  387. package/dist/render/rendererHarness.js +185 -0
  388. package/dist/render/resolutionGovernor.d.ts +107 -0
  389. package/dist/render/resolutionGovernor.js +144 -0
  390. package/dist/render/scatterDeform.d.ts +17 -0
  391. package/dist/render/scatterDeform.js +46 -0
  392. package/dist/render/sceneTarget.d.ts +288 -0
  393. package/dist/render/sceneTarget.js +856 -0
  394. package/dist/render/screenSpaceReflection.d.ts +233 -0
  395. package/dist/render/screenSpaceReflection.js +415 -0
  396. package/dist/render/sdfFont.d.ts +77 -0
  397. package/dist/render/sdfFont.js +86 -0
  398. package/dist/render/sdfTextLayout.d.ts +46 -0
  399. package/dist/render/sdfTextLayout.js +145 -0
  400. package/dist/render/sdfTextRenderer.d.ts +75 -0
  401. package/dist/render/sdfTextRenderer.js +194 -0
  402. package/dist/render/seaState.d.ts +25 -0
  403. package/dist/render/seaState.js +34 -0
  404. package/dist/render/segmentQuads.d.ts +29 -0
  405. package/dist/render/segmentQuads.js +75 -0
  406. package/dist/render/shader.d.ts +5 -0
  407. package/dist/render/shader.js +172 -0
  408. package/dist/render/shaders/ambientOcclusion.d.ts +45 -0
  409. package/dist/render/shaders/ambientOcclusion.js +352 -0
  410. package/dist/render/shaders/arcane.d.ts +19 -0
  411. package/dist/render/shaders/arcane.js +102 -0
  412. package/dist/render/shaders/bloom.d.ts +70 -0
  413. package/dist/render/shaders/bloom.js +227 -0
  414. package/dist/render/shaders/bolt.d.ts +17 -0
  415. package/dist/render/shaders/bolt.js +161 -0
  416. package/dist/render/shaders/caustics.d.ts +38 -0
  417. package/dist/render/shaders/caustics.js +167 -0
  418. package/dist/render/shaders/conditionals.d.ts +21 -0
  419. package/dist/render/shaders/conditionals.js +55 -0
  420. package/dist/render/shaders/decalProject.d.ts +25 -0
  421. package/dist/render/shaders/decalProject.js +125 -0
  422. package/dist/render/shaders/depth.d.ts +14 -0
  423. package/dist/render/shaders/depth.js +114 -0
  424. package/dist/render/shaders/depthOfField.d.ts +41 -0
  425. package/dist/render/shaders/depthOfField.js +139 -0
  426. package/dist/render/shaders/film.d.ts +15 -0
  427. package/dist/render/shaders/film.js +283 -0
  428. package/dist/render/shaders/fire.d.ts +12 -0
  429. package/dist/render/shaders/fire.js +178 -0
  430. package/dist/render/shaders/flat/directionalShadow.d.ts +1 -0
  431. package/dist/render/shaders/flat/directionalShadow.js +195 -0
  432. package/dist/render/shaders/flat/index.d.ts +135 -0
  433. package/dist/render/shaders/flat/index.js +387 -0
  434. package/dist/render/shaders/flat/lobes.d.ts +1 -0
  435. package/dist/render/shaders/flat/lobes.js +398 -0
  436. package/dist/render/shaders/flat/main.d.ts +2 -0
  437. package/dist/render/shaders/flat/main.js +1630 -0
  438. package/dist/render/shaders/flat/pointShadow.d.ts +1 -0
  439. package/dist/render/shaders/flat/pointShadow.js +322 -0
  440. package/dist/render/shaders/flat/preamble.d.ts +15 -0
  441. package/dist/render/shaders/flat/preamble.js +864 -0
  442. package/dist/render/shaders/flat/probeGrid.d.ts +21 -0
  443. package/dist/render/shaders/flat/probeGrid.js +151 -0
  444. package/dist/render/shaders/flat/surface.d.ts +2 -0
  445. package/dist/render/shaders/flat/surface.js +40 -0
  446. package/dist/render/shaders/flock.d.ts +11 -0
  447. package/dist/render/shaders/flock.js +102 -0
  448. package/dist/render/shaders/fog.d.ts +37 -0
  449. package/dist/render/shaders/fog.js +98 -0
  450. package/dist/render/shaders/fullscreen.d.ts +16 -0
  451. package/dist/render/shaders/fullscreen.js +27 -0
  452. package/dist/render/shaders/generated/ambientOcclusion.wgsl.d.ts +65 -0
  453. package/dist/render/shaders/generated/ambientOcclusion.wgsl.js +71 -0
  454. package/dist/render/shaders/generated/arcane.wgsl.d.ts +90 -0
  455. package/dist/render/shaders/generated/arcane.wgsl.js +96 -0
  456. package/dist/render/shaders/generated/bloom.wgsl.d.ts +69 -0
  457. package/dist/render/shaders/generated/bloom.wgsl.js +75 -0
  458. package/dist/render/shaders/generated/bolt.wgsl.d.ts +118 -0
  459. package/dist/render/shaders/generated/bolt.wgsl.js +124 -0
  460. package/dist/render/shaders/generated/caustics.wgsl.d.ts +118 -0
  461. package/dist/render/shaders/generated/caustics.wgsl.js +124 -0
  462. package/dist/render/shaders/generated/decalProject.wgsl.d.ts +61 -0
  463. package/dist/render/shaders/generated/decalProject.wgsl.js +67 -0
  464. package/dist/render/shaders/generated/depth.wgsl.d.ts +131 -0
  465. package/dist/render/shaders/generated/depth.wgsl.js +137 -0
  466. package/dist/render/shaders/generated/film.wgsl.d.ts +134 -0
  467. package/dist/render/shaders/generated/film.wgsl.js +140 -0
  468. package/dist/render/shaders/generated/fire.wgsl.d.ts +128 -0
  469. package/dist/render/shaders/generated/fire.wgsl.js +134 -0
  470. package/dist/render/shaders/generated/flat.wgsl.d.ts +9163 -0
  471. package/dist/render/shaders/generated/flat.wgsl.js +9192 -0
  472. package/dist/render/shaders/generated/flock.wgsl.d.ts +73 -0
  473. package/dist/render/shaders/generated/flock.wgsl.js +79 -0
  474. package/dist/render/shaders/generated/fullscreen.wgsl.d.ts +12 -0
  475. package/dist/render/shaders/generated/fullscreen.wgsl.js +18 -0
  476. package/dist/render/shaders/generated/globalMedium.wgsl.d.ts +130 -0
  477. package/dist/render/shaders/generated/globalMedium.wgsl.js +136 -0
  478. package/dist/render/shaders/generated/lightVolume.wgsl.d.ts +230 -0
  479. package/dist/render/shaders/generated/lightVolume.wgsl.js +239 -0
  480. package/dist/render/shaders/generated/line.wgsl.d.ts +128 -0
  481. package/dist/render/shaders/generated/line.wgsl.js +134 -0
  482. package/dist/render/shaders/generated/octahedralResolve.wgsl.d.ts +51 -0
  483. package/dist/render/shaders/generated/octahedralResolve.wgsl.js +57 -0
  484. package/dist/render/shaders/generated/oitResolve.wgsl.d.ts +23 -0
  485. package/dist/render/shaders/generated/oitResolve.wgsl.js +29 -0
  486. package/dist/render/shaders/generated/panel.wgsl.d.ts +48 -0
  487. package/dist/render/shaders/generated/panel.wgsl.js +54 -0
  488. package/dist/render/shaders/generated/particle.wgsl.d.ts +332 -0
  489. package/dist/render/shaders/generated/particle.wgsl.js +338 -0
  490. package/dist/render/shaders/generated/prefilter.wgsl.d.ts +61 -0
  491. package/dist/render/shaders/generated/prefilter.wgsl.js +67 -0
  492. package/dist/render/shaders/generated/rush.wgsl.d.ts +131 -0
  493. package/dist/render/shaders/generated/rush.wgsl.js +137 -0
  494. package/dist/render/shaders/generated/scatter.wgsl.d.ts +195 -0
  495. package/dist/render/shaders/generated/scatter.wgsl.js +201 -0
  496. package/dist/render/shaders/generated/sdfText.wgsl.d.ts +69 -0
  497. package/dist/render/shaders/generated/sdfText.wgsl.js +75 -0
  498. package/dist/render/shaders/generated/sky.wgsl.d.ts +100 -0
  499. package/dist/render/shaders/generated/sky.wgsl.js +106 -0
  500. package/dist/render/shaders/generated/smoke.wgsl.d.ts +85 -0
  501. package/dist/render/shaders/generated/smoke.wgsl.js +91 -0
  502. package/dist/render/shaders/generated/ssrResolve.wgsl.d.ts +18 -0
  503. package/dist/render/shaders/generated/ssrResolve.wgsl.js +24 -0
  504. package/dist/render/shaders/generated/ssrTrace.wgsl.d.ts +86 -0
  505. package/dist/render/shaders/generated/ssrTrace.wgsl.js +92 -0
  506. package/dist/render/shaders/generated/temporalResolve.wgsl.d.ts +46 -0
  507. package/dist/render/shaders/generated/temporalResolve.wgsl.js +52 -0
  508. package/dist/render/shaders/generated/text.wgsl.d.ts +98 -0
  509. package/dist/render/shaders/generated/text.wgsl.js +104 -0
  510. package/dist/render/shaders/generated/water.wgsl.d.ts +247 -0
  511. package/dist/render/shaders/generated/water.wgsl.js +253 -0
  512. package/dist/render/shaders/generated/windStreaks.wgsl.d.ts +73 -0
  513. package/dist/render/shaders/generated/windStreaks.wgsl.js +79 -0
  514. package/dist/render/shaders/gerstner.d.ts +21 -0
  515. package/dist/render/shaders/gerstner.js +110 -0
  516. package/dist/render/shaders/globalMedium.d.ts +56 -0
  517. package/dist/render/shaders/globalMedium.js +393 -0
  518. package/dist/render/shaders/lightVolume.d.ts +61 -0
  519. package/dist/render/shaders/lightVolume.js +527 -0
  520. package/dist/render/shaders/line.d.ts +18 -0
  521. package/dist/render/shaders/line.js +122 -0
  522. package/dist/render/shaders/morph.d.ts +26 -0
  523. package/dist/render/shaders/morph.js +61 -0
  524. package/dist/render/shaders/octahedral.d.ts +76 -0
  525. package/dist/render/shaders/octahedral.js +161 -0
  526. package/dist/render/shaders/octahedralResolve.d.ts +25 -0
  527. package/dist/render/shaders/octahedralResolve.js +81 -0
  528. package/dist/render/shaders/oitResolve.d.ts +17 -0
  529. package/dist/render/shaders/oitResolve.js +42 -0
  530. package/dist/render/shaders/outputTransform.d.ts +37 -0
  531. package/dist/render/shaders/outputTransform.js +106 -0
  532. package/dist/render/shaders/panel.d.ts +17 -0
  533. package/dist/render/shaders/panel.js +50 -0
  534. package/dist/render/shaders/particle.d.ts +82 -0
  535. package/dist/render/shaders/particle.js +431 -0
  536. package/dist/render/shaders/prefilter.d.ts +37 -0
  537. package/dist/render/shaders/prefilter.js +276 -0
  538. package/dist/render/shaders/rush.d.ts +21 -0
  539. package/dist/render/shaders/rush.js +355 -0
  540. package/dist/render/shaders/scatter.d.ts +14 -0
  541. package/dist/render/shaders/scatter.js +206 -0
  542. package/dist/render/shaders/sdfText.d.ts +9 -0
  543. package/dist/render/shaders/sdfText.js +65 -0
  544. package/dist/render/shaders/skinning.d.ts +17 -0
  545. package/dist/render/shaders/skinning.js +59 -0
  546. package/dist/render/shaders/sky.d.ts +10 -0
  547. package/dist/render/shaders/sky.js +242 -0
  548. package/dist/render/shaders/smoke.d.ts +8 -0
  549. package/dist/render/shaders/smoke.js +88 -0
  550. package/dist/render/shaders/ssrResolve.d.ts +15 -0
  551. package/dist/render/shaders/ssrResolve.js +28 -0
  552. package/dist/render/shaders/ssrTrace.d.ts +22 -0
  553. package/dist/render/shaders/ssrTrace.js +230 -0
  554. package/dist/render/shaders/tangentFrame.d.ts +17 -0
  555. package/dist/render/shaders/tangentFrame.js +70 -0
  556. package/dist/render/shaders/temporalResolve.d.ts +1 -0
  557. package/dist/render/shaders/temporalResolve.js +150 -0
  558. package/dist/render/shaders/text.d.ts +17 -0
  559. package/dist/render/shaders/text.js +155 -0
  560. package/dist/render/shaders/vertexChannel.d.ts +39 -0
  561. package/dist/render/shaders/vertexChannel.js +69 -0
  562. package/dist/render/shaders/water.d.ts +18 -0
  563. package/dist/render/shaders/water.js +354 -0
  564. package/dist/render/shaders/windStreaks.d.ts +14 -0
  565. package/dist/render/shaders/windStreaks.js +129 -0
  566. package/dist/render/shadowCasters.d.ts +107 -0
  567. package/dist/render/shadowCasters.js +1 -0
  568. package/dist/render/shadowMap.d.ts +10 -0
  569. package/dist/render/shadowMap.js +80 -0
  570. package/dist/render/shotPlacement.d.ts +80 -0
  571. package/dist/render/shotPlacement.js +183 -0
  572. package/dist/render/skinPalette.d.ts +90 -0
  573. package/dist/render/skinPalette.js +136 -0
  574. package/dist/render/ssrPass.d.ts +59 -0
  575. package/dist/render/ssrPass.js +196 -0
  576. package/dist/render/surfaceSheet.d.ts +52 -0
  577. package/dist/render/surfaceSheet.js +99 -0
  578. package/dist/render/surfaceTexture.d.ts +197 -0
  579. package/dist/render/surfaceTexture.js +116 -0
  580. package/dist/render/temporalAa.d.ts +104 -0
  581. package/dist/render/temporalAa.js +194 -0
  582. package/dist/render/temporalPass.d.ts +54 -0
  583. package/dist/render/temporalPass.js +135 -0
  584. package/dist/render/textLayout.d.ts +88 -0
  585. package/dist/render/textLayout.js +201 -0
  586. package/dist/render/textRenderer.d.ts +32 -0
  587. package/dist/render/textRenderer.js +176 -0
  588. package/dist/render/thirdPersonCamera.d.ts +272 -0
  589. package/dist/render/thirdPersonCamera.js +479 -0
  590. package/dist/render/trample.d.ts +57 -0
  591. package/dist/render/trample.js +134 -0
  592. package/dist/render/translucentQueue.d.ts +76 -0
  593. package/dist/render/translucentQueue.js +90 -0
  594. package/dist/render/uniformVectorBudget.d.ts +105 -0
  595. package/dist/render/uniformVectorBudget.js +201 -0
  596. package/dist/render/uploadStep.d.ts +14 -0
  597. package/dist/render/uploadStep.js +14 -0
  598. package/dist/render/vertexDefaults.d.ts +48 -0
  599. package/dist/render/vertexDefaults.js +111 -0
  600. package/dist/render/visibility.d.ts +22 -0
  601. package/dist/render/visibility.js +47 -0
  602. package/dist/render/waterDraw.d.ts +57 -0
  603. package/dist/render/waterDraw.js +102 -0
  604. package/dist/render/waterGrid.d.ts +62 -0
  605. package/dist/render/waterGrid.js +151 -0
  606. package/dist/render/waterRenderer.d.ts +163 -0
  607. package/dist/render/waterRenderer.js +165 -0
  608. package/dist/render/wind.d.ts +45 -0
  609. package/dist/render/wind.js +32 -0
  610. package/dist/render/windField.d.ts +34 -0
  611. package/dist/render/windField.js +13 -0
  612. package/dist/render/windStreakDraw.d.ts +73 -0
  613. package/dist/render/windStreakDraw.js +86 -0
  614. package/dist/render/windStreakRenderer.d.ts +37 -0
  615. package/dist/render/windStreakRenderer.js +86 -0
  616. package/dist/scene/node.d.ts +128 -0
  617. package/dist/scene/node.js +319 -0
  618. package/dist/scene/visit.d.ts +38 -0
  619. package/dist/scene/visit.js +43 -0
  620. package/dist/ui/clipMime.d.ts +46 -0
  621. package/dist/ui/clipMime.js +88 -0
  622. package/dist/ui/exportTarget.d.ts +305 -0
  623. package/dist/ui/exportTarget.js +368 -0
  624. package/dist/ui/frameOverlay.d.ts +59 -0
  625. package/dist/ui/frameOverlay.js +76 -0
  626. package/dist/ui/framePacer.d.ts +142 -0
  627. package/dist/ui/framePacer.js +284 -0
  628. package/dist/ui/frameRecorder.d.ts +188 -0
  629. package/dist/ui/frameRecorder.js +221 -0
  630. package/dist/ui/fullscreen.d.ts +72 -0
  631. package/dist/ui/fullscreen.js +92 -0
  632. package/dist/ui/pixelCursor.d.ts +28 -0
  633. package/dist/ui/pixelCursor.js +66 -0
  634. package/dist/ui/splash.d.ts +86 -0
  635. package/dist/ui/splash.js +300 -0
  636. package/dist/ui/stillFrame.d.ts +22 -0
  637. package/dist/ui/stillFrame.js +40 -0
  638. package/package.json +60 -0
  639. package/src/behavior/behaviorTree.ts +346 -0
  640. package/src/build/shaderComments.ts +0 -0
  641. package/src/cinematic/player.ts +209 -0
  642. package/src/cinematic/script.ts +231 -0
  643. package/src/core/bootGate.ts +49 -0
  644. package/src/core/loadTracker.ts +144 -0
  645. package/src/core/loop.ts +211 -0
  646. package/src/core/messageQueue.ts +145 -0
  647. package/src/core/onceSet.ts +65 -0
  648. package/src/core/preferences.ts +177 -0
  649. package/src/core/remoteSave.ts +347 -0
  650. package/src/core/rng.ts +101 -0
  651. package/src/core/stepBudget.ts +136 -0
  652. package/src/core/storage.ts +114 -0
  653. package/src/core/tickTrace.ts +129 -0
  654. package/src/core/timeCurve.ts +175 -0
  655. package/src/core/withDefaults.ts +28 -0
  656. package/src/dev/contactProbe.ts +115 -0
  657. package/src/dev/fpsMeter.ts +101 -0
  658. package/src/environment/celestialClock.ts +385 -0
  659. package/src/geometry/decal.ts +260 -0
  660. package/src/geometry/filmPatch.ts +158 -0
  661. package/src/geometry/growable.ts +165 -0
  662. package/src/geometry/lightVolume.ts +161 -0
  663. package/src/geometry/meshBuilder.ts +1397 -0
  664. package/src/geometry/pixelFont.ts +189 -0
  665. package/src/geometry/ribbon.ts +790 -0
  666. package/src/geometry/shellFill.ts +265 -0
  667. package/src/geometry/spline.ts +659 -0
  668. package/src/geometry/tangents.ts +173 -0
  669. package/src/geometry/textMesh.ts +96 -0
  670. package/src/geometry/treeBuilder.ts +114 -0
  671. package/src/host/display.ts +180 -0
  672. package/src/host/files.ts +77 -0
  673. package/src/host/lifecycle.ts +63 -0
  674. package/src/host/platformServices.ts +23 -0
  675. package/src/host/screen.ts +134 -0
  676. package/src/index.ts +730 -0
  677. package/src/input/actionMap.ts +377 -0
  678. package/src/input/activeDevice.ts +86 -0
  679. package/src/input/gamepadIdentity.ts +131 -0
  680. package/src/input/gamepadMapping.ts +121 -0
  681. package/src/input/input.ts +872 -0
  682. package/src/input/inputHarness.ts +226 -0
  683. package/src/input/rightGesture.ts +76 -0
  684. package/src/input/rumble.ts +138 -0
  685. package/src/input/touchControls.ts +451 -0
  686. package/src/input/typingTarget.ts +26 -0
  687. package/src/math/bounds.ts +153 -0
  688. package/src/math/color.ts +37 -0
  689. package/src/math/exact.ts +274 -0
  690. package/src/math/frustum.ts +115 -0
  691. package/src/math/intersect.ts +228 -0
  692. package/src/math/scalar.ts +109 -0
  693. package/src/math/spring.ts +106 -0
  694. package/src/nav/navGraph.ts +168 -0
  695. package/src/nav/navPath.ts +217 -0
  696. package/src/nav/navSearch.ts +200 -0
  697. package/src/physics/boxSurface.ts +96 -0
  698. package/src/physics/colliderSurface.ts +213 -0
  699. package/src/physics/compositeSurface.ts +111 -0
  700. package/src/physics/heightSurface.ts +234 -0
  701. package/src/physics/ribbonSurface.ts +642 -0
  702. package/src/render/ambientOcclusionPass.ts +200 -0
  703. package/src/render/areaLights.ts +194 -0
  704. package/src/render/areaShadowSet.ts +405 -0
  705. package/src/render/atmosphere.ts +186 -0
  706. package/src/render/backend/api.ts +802 -0
  707. package/src/render/backend/budget.ts +139 -0
  708. package/src/render/backend/createRenderer.ts +343 -0
  709. package/src/render/backend/deadline.ts +37 -0
  710. package/src/render/backend/probe.ts +152 -0
  711. package/src/render/backend/select.ts +288 -0
  712. package/src/render/backend/timer.ts +59 -0
  713. package/src/render/backend/webgl2/instanced.ts +46 -0
  714. package/src/render/backend/webgl2/morphTexture.ts +58 -0
  715. package/src/render/backend/webgl2/renderer.ts +7484 -0
  716. package/src/render/backend/webgl2/skinPaletteTexture.ts +70 -0
  717. package/src/render/backend/webgpu/boltPass.ts +205 -0
  718. package/src/render/backend/webgpu/buffers.ts +553 -0
  719. package/src/render/backend/webgpu/causticsPass.ts +174 -0
  720. package/src/render/backend/webgpu/clusterBinner.ts +259 -0
  721. package/src/render/backend/webgpu/depthPass.ts +261 -0
  722. package/src/render/backend/webgpu/device.ts +148 -0
  723. package/src/render/backend/webgpu/drawCommand.ts +79 -0
  724. package/src/render/backend/webgpu/environmentTexels.ts +96 -0
  725. package/src/render/backend/webgpu/filmPass.ts +123 -0
  726. package/src/render/backend/webgpu/flatPass.ts +635 -0
  727. package/src/render/backend/webgpu/flockPass.ts +163 -0
  728. package/src/render/backend/webgpu/gpuTimestamps.ts +255 -0
  729. package/src/render/backend/webgpu/insetPass.ts +123 -0
  730. package/src/render/backend/webgpu/instanced.ts +55 -0
  731. package/src/render/backend/webgpu/lightVolumePass.ts +203 -0
  732. package/src/render/backend/webgpu/linePass.ts +270 -0
  733. package/src/render/backend/webgpu/morphTexture.ts +61 -0
  734. package/src/render/backend/webgpu/panelPass.ts +138 -0
  735. package/src/render/backend/webgpu/particlePass.ts +370 -0
  736. package/src/render/backend/webgpu/pipelineCache.ts +152 -0
  737. package/src/render/backend/webgpu/plumePass.ts +292 -0
  738. package/src/render/backend/webgpu/pointShadowPass.ts +368 -0
  739. package/src/render/backend/webgpu/postPass.ts +470 -0
  740. package/src/render/backend/webgpu/probePass.ts +218 -0
  741. package/src/render/backend/webgpu/reflectionPass.ts +137 -0
  742. package/src/render/backend/webgpu/renderer.ts +13004 -0
  743. package/src/render/backend/webgpu/scatterPass.ts +354 -0
  744. package/src/render/backend/webgpu/sdfTextPass.ts +220 -0
  745. package/src/render/backend/webgpu/shaderModules.ts +49 -0
  746. package/src/render/backend/webgpu/shaders/clusterBin.wgsl.ts +219 -0
  747. package/src/render/backend/webgpu/skinPaletteRing.ts +105 -0
  748. package/src/render/backend/webgpu/skinPaletteTexture.ts +79 -0
  749. package/src/render/backend/webgpu/skyPass.ts +85 -0
  750. package/src/render/backend/webgpu/surfaceTexturePass.ts +257 -0
  751. package/src/render/backend/webgpu/textPass.ts +224 -0
  752. package/src/render/backend/webgpu/uniformRing.ts +228 -0
  753. package/src/render/backend/webgpu/waterPass.ts +211 -0
  754. package/src/render/backend/webgpu/windStreakPass.ts +196 -0
  755. package/src/render/billboard.ts +108 -0
  756. package/src/render/bloomChain.ts +101 -0
  757. package/src/render/bloomPass.ts +256 -0
  758. package/src/render/boltBatch.ts +141 -0
  759. package/src/render/boltPool.ts +360 -0
  760. package/src/render/boom.ts +123 -0
  761. package/src/render/camera.ts +348 -0
  762. package/src/render/causticsRenderer.ts +171 -0
  763. package/src/render/cinematicCamera.ts +278 -0
  764. package/src/render/clusteredLights.ts +598 -0
  765. package/src/render/colourGrade.ts +109 -0
  766. package/src/render/compute.ts +83 -0
  767. package/src/render/contextLoss.ts +50 -0
  768. package/src/render/debugLines.ts +411 -0
  769. package/src/render/decalPass.ts +124 -0
  770. package/src/render/decalProjector.ts +390 -0
  771. package/src/render/decalQueue.ts +110 -0
  772. package/src/render/depthConvention.ts +383 -0
  773. package/src/render/drawingBuffer.ts +89 -0
  774. package/src/render/emptyTexture.ts +130 -0
  775. package/src/render/envProbeArray.ts +201 -0
  776. package/src/render/equirectToCube.ts +160 -0
  777. package/src/render/flockGeometry.ts +53 -0
  778. package/src/render/flockRenderer.ts +111 -0
  779. package/src/render/frame/arena.ts +93 -0
  780. package/src/render/frame/index.ts +29 -0
  781. package/src/render/frame/replay.ts +50 -0
  782. package/src/render/frame/resources.ts +61 -0
  783. package/src/render/frame/schedule.ts +85 -0
  784. package/src/render/frameView.ts +20 -0
  785. package/src/render/gizmo.ts +923 -0
  786. package/src/render/globalMedium.ts +154 -0
  787. package/src/render/globalMediumPass.ts +323 -0
  788. package/src/render/gpuCapability.ts +244 -0
  789. package/src/render/gpuTimer.ts +182 -0
  790. package/src/render/halfFloat.ts +39 -0
  791. package/src/render/handleRegistry.ts +96 -0
  792. package/src/render/iesProfile.ts +215 -0
  793. package/src/render/imageTexels.ts +109 -0
  794. package/src/render/instancedMesh.ts +187 -0
  795. package/src/render/instances.ts +92 -0
  796. package/src/render/lightBudget.ts +655 -0
  797. package/src/render/lightMatrix.ts +69 -0
  798. package/src/render/lightVolumeDraw.ts +216 -0
  799. package/src/render/lineBatch.ts +180 -0
  800. package/src/render/linePoints.ts +61 -0
  801. package/src/render/livePointShadowSet.ts +285 -0
  802. package/src/render/lod.ts +86 -0
  803. package/src/render/mesh.ts +536 -0
  804. package/src/render/occlusion.ts +406 -0
  805. package/src/render/oitPass.ts +230 -0
  806. package/src/render/orderIndependent.ts +136 -0
  807. package/src/render/particleBatch.ts +299 -0
  808. package/src/render/particleMaterial.ts +84 -0
  809. package/src/render/particlePool.ts +291 -0
  810. package/src/render/pass.ts +203 -0
  811. package/src/render/passTarget.ts +225 -0
  812. package/src/render/pickable.ts +222 -0
  813. package/src/render/planarReflection.ts +233 -0
  814. package/src/render/planarReflectionDraw.ts +87 -0
  815. package/src/render/plumeGeometry.ts +75 -0
  816. package/src/render/plumeMaterial.ts +99 -0
  817. package/src/render/plumeRenderer.ts +272 -0
  818. package/src/render/pointLightSelection.ts +447 -0
  819. package/src/render/pointShadowArray.ts +276 -0
  820. package/src/render/pointShadowBudget.ts +305 -0
  821. package/src/render/pointShadowImage.ts +470 -0
  822. package/src/render/pointShadowMap.ts +228 -0
  823. package/src/render/pointShadowSystem.ts +408 -0
  824. package/src/render/prefilterEnvMap.ts +162 -0
  825. package/src/render/prefilterPass.ts +115 -0
  826. package/src/render/probeGrid.ts +248 -0
  827. package/src/render/rainField.ts +240 -0
  828. package/src/render/reflectionProbe.ts +530 -0
  829. package/src/render/renderQuality.ts +1054 -0
  830. package/src/render/rendererHarness.ts +214 -0
  831. package/src/render/resolutionGovernor.ts +189 -0
  832. package/src/render/scatterDeform.ts +72 -0
  833. package/src/render/sceneTarget.ts +1032 -0
  834. package/src/render/screenSpaceReflection.ts +524 -0
  835. package/src/render/sdfFont.ts +157 -0
  836. package/src/render/sdfTextLayout.ts +206 -0
  837. package/src/render/sdfTextRenderer.ts +233 -0
  838. package/src/render/seaState.ts +55 -0
  839. package/src/render/segmentQuads.ts +92 -0
  840. package/src/render/shader.ts +190 -0
  841. package/src/render/shaders/ambientOcclusion.ts +354 -0
  842. package/src/render/shaders/arcane.ts +103 -0
  843. package/src/render/shaders/bloom.ts +232 -0
  844. package/src/render/shaders/bolt.ts +164 -0
  845. package/src/render/shaders/caustics.ts +169 -0
  846. package/src/render/shaders/conditionals.ts +58 -0
  847. package/src/render/shaders/decalProject.ts +127 -0
  848. package/src/render/shaders/depth.ts +131 -0
  849. package/src/render/shaders/depthOfField.ts +141 -0
  850. package/src/render/shaders/film.ts +285 -0
  851. package/src/render/shaders/fire.ts +180 -0
  852. package/src/render/shaders/flat/directionalShadow.ts +196 -0
  853. package/src/render/shaders/flat/index.ts +502 -0
  854. package/src/render/shaders/flat/lobes.ts +399 -0
  855. package/src/render/shaders/flat/main.ts +1631 -0
  856. package/src/render/shaders/flat/pointShadow.ts +323 -0
  857. package/src/render/shaders/flat/preamble.ts +875 -0
  858. package/src/render/shaders/flat/probeGrid.ts +152 -0
  859. package/src/render/shaders/flat/surface.ts +41 -0
  860. package/src/render/shaders/flock.ts +103 -0
  861. package/src/render/shaders/fog.ts +99 -0
  862. package/src/render/shaders/fullscreen.ts +28 -0
  863. package/src/render/shaders/generated/ambientOcclusion.wgsl.ts +74 -0
  864. package/src/render/shaders/generated/arcane.wgsl.ts +98 -0
  865. package/src/render/shaders/generated/bloom.wgsl.ts +79 -0
  866. package/src/render/shaders/generated/bolt.wgsl.ts +127 -0
  867. package/src/render/shaders/generated/caustics.wgsl.ts +127 -0
  868. package/src/render/shaders/generated/decalProject.wgsl.ts +69 -0
  869. package/src/render/shaders/generated/depth.wgsl.ts +142 -0
  870. package/src/render/shaders/generated/film.wgsl.ts +143 -0
  871. package/src/render/shaders/generated/fire.wgsl.ts +137 -0
  872. package/src/render/shaders/generated/flat.wgsl.ts +9195 -0
  873. package/src/render/shaders/generated/flock.wgsl.ts +82 -0
  874. package/src/render/shaders/generated/fullscreen.wgsl.ts +20 -0
  875. package/src/render/shaders/generated/globalMedium.wgsl.ts +139 -0
  876. package/src/render/shaders/generated/lightVolume.wgsl.ts +242 -0
  877. package/src/render/shaders/generated/line.wgsl.ts +137 -0
  878. package/src/render/shaders/generated/octahedralResolve.wgsl.ts +60 -0
  879. package/src/render/shaders/generated/oitResolve.wgsl.ts +31 -0
  880. package/src/render/shaders/generated/panel.wgsl.ts +57 -0
  881. package/src/render/shaders/generated/particle.wgsl.ts +343 -0
  882. package/src/render/shaders/generated/prefilter.wgsl.ts +69 -0
  883. package/src/render/shaders/generated/rush.wgsl.ts +139 -0
  884. package/src/render/shaders/generated/scatter.wgsl.ts +205 -0
  885. package/src/render/shaders/generated/sdfText.wgsl.ts +78 -0
  886. package/src/render/shaders/generated/sky.wgsl.ts +109 -0
  887. package/src/render/shaders/generated/smoke.wgsl.ts +93 -0
  888. package/src/render/shaders/generated/ssrResolve.wgsl.ts +26 -0
  889. package/src/render/shaders/generated/ssrTrace.wgsl.ts +94 -0
  890. package/src/render/shaders/generated/temporalResolve.wgsl.ts +54 -0
  891. package/src/render/shaders/generated/text.wgsl.ts +107 -0
  892. package/src/render/shaders/generated/water.wgsl.ts +256 -0
  893. package/src/render/shaders/generated/windStreaks.wgsl.ts +82 -0
  894. package/src/render/shaders/gerstner.ts +110 -0
  895. package/src/render/shaders/globalMedium.ts +396 -0
  896. package/src/render/shaders/lightVolume.ts +546 -0
  897. package/src/render/shaders/line.ts +125 -0
  898. package/src/render/shaders/morph.ts +62 -0
  899. package/src/render/shaders/octahedral.ts +170 -0
  900. package/src/render/shaders/octahedralResolve.ts +83 -0
  901. package/src/render/shaders/oitResolve.ts +42 -0
  902. package/src/render/shaders/outputTransform.ts +107 -0
  903. package/src/render/shaders/panel.ts +51 -0
  904. package/src/render/shaders/particle.ts +438 -0
  905. package/src/render/shaders/prefilter.ts +278 -0
  906. package/src/render/shaders/rush.ts +357 -0
  907. package/src/render/shaders/scatter.ts +211 -0
  908. package/src/render/shaders/sdfText.ts +68 -0
  909. package/src/render/shaders/skinning.ts +59 -0
  910. package/src/render/shaders/sky.ts +243 -0
  911. package/src/render/shaders/smoke.ts +89 -0
  912. package/src/render/shaders/ssrResolve.ts +28 -0
  913. package/src/render/shaders/ssrTrace.ts +233 -0
  914. package/src/render/shaders/tangentFrame.ts +70 -0
  915. package/src/render/shaders/temporalResolve.ts +151 -0
  916. package/src/render/shaders/text.ts +156 -0
  917. package/src/render/shaders/vertexChannel.ts +71 -0
  918. package/src/render/shaders/water.ts +356 -0
  919. package/src/render/shaders/windStreaks.ts +130 -0
  920. package/src/render/shadowCasters.ts +124 -0
  921. package/src/render/shadowMap.ts +89 -0
  922. package/src/render/shotPlacement.ts +266 -0
  923. package/src/render/skinPalette.ts +157 -0
  924. package/src/render/ssrPass.ts +241 -0
  925. package/src/render/surfaceSheet.ts +158 -0
  926. package/src/render/surfaceTexture.ts +310 -0
  927. package/src/render/temporalAa.ts +221 -0
  928. package/src/render/temporalPass.ts +153 -0
  929. package/src/render/textLayout.ts +239 -0
  930. package/src/render/textRenderer.ts +201 -0
  931. package/src/render/thirdPersonCamera.ts +578 -0
  932. package/src/render/trample.ts +140 -0
  933. package/src/render/translucentQueue.ts +161 -0
  934. package/src/render/uniformVectorBudget.ts +246 -0
  935. package/src/render/uploadStep.ts +14 -0
  936. package/src/render/vertexDefaults.ts +115 -0
  937. package/src/render/visibility.ts +56 -0
  938. package/src/render/waterDraw.ts +167 -0
  939. package/src/render/waterGrid.ts +180 -0
  940. package/src/render/waterRenderer.ts +352 -0
  941. package/src/render/wind.ts +79 -0
  942. package/src/render/windField.ts +50 -0
  943. package/src/render/windStreakDraw.ts +131 -0
  944. package/src/render/windStreakRenderer.ts +130 -0
  945. package/src/scene/node.ts +336 -0
  946. package/src/scene/visit.ts +82 -0
  947. package/src/ui/clipMime.ts +109 -0
  948. package/src/ui/exportTarget.ts +491 -0
  949. package/src/ui/frameOverlay.ts +159 -0
  950. package/src/ui/framePacer.ts +351 -0
  951. package/src/ui/frameRecorder.ts +333 -0
  952. package/src/ui/fullscreen.ts +113 -0
  953. package/src/ui/pixelCursor.ts +99 -0
  954. package/src/ui/splash.ts +347 -0
  955. package/src/ui/stillFrame.ts +44 -0
@@ -0,0 +1,872 @@
1
+ /**
2
+ * Low-level, device-agnostic input capture: raw keys, relative mouse motion,
3
+ * live touch points. Interpretation (bindings, gestures, virtual stick) is the
4
+ * game's job — this module never decides what an input *means*.
5
+ */
6
+
7
+ import { isTypingTarget } from './typingTarget.ts';
8
+ import { ActiveDevice, type InputDevice } from './activeDevice.ts';
9
+ import { glyphFor, identifyGamepad, labelFor, type GamepadFamily } from './gamepadIdentity.ts';
10
+ import {
11
+ AXIS_INDEX,
12
+ BUTTON_INDEX,
13
+ DEFAULT_DEADZONE,
14
+ applyDeadzone,
15
+ type GamepadAxis,
16
+ type GamepadButton,
17
+ } from './gamepadMapping.ts';
18
+ import { type RawHapticActuator, playRumble, stopRumble } from './rumble.ts';
19
+
20
+ /**
21
+ * Ask for the pointer lock, and deal with being told no.
22
+ *
23
+ * Split out from the caller below so the rule can be tested without a DOM, the
24
+ * same way `isTypingTarget` is.
25
+ *
26
+ * **The refusal is expected and it is not an error.** Chrome returns a promise here
27
+ * (113 and up) and rejects it when it will not grant the lock — most often for the
28
+ * second or so after the user has left one with Escape, which is precisely when the
29
+ * next click arrives asking for it back. Dropping that promise makes an ordinary
30
+ * refusal an `unhandledrejection`, and in a game that watches for those it becomes a
31
+ * bug report about nothing: see report `G94666`, 2026-08-08.
32
+ *
33
+ * `requestFullscreen` next door has always caught its own for the same reason.
34
+ */
35
+ export function askForPointerLock(
36
+ request: (options?: { unadjustedMovement: boolean }) => Promise<void> | void,
37
+ ): void {
38
+ /*
39
+ * **Asked for without the operating system's pointer acceleration on it.**
40
+ *
41
+ * `movementX` is a *display* delta by default, so the pointer curve the desktop applies to a
42
+ * cursor is applied to the camera as well: a slow hand is scaled toward nothing and a fast one
43
+ * is scaled up, which is a camera that ignores small movements and then jumps. Reported from
44
+ * Firefox on Linux as "if I move slowly it does not move, and if I accelerate it moves steppy,
45
+ * not because the frame rate is low" — which is the acceleration curve described exactly, by
46
+ * somebody who could tell it was not the frame rate.
47
+ *
48
+ * A game wants the device's own counts. `unadjustedMovement` is how the specification says so,
49
+ * and it is per request rather than a setting, so it belongs here rather than at a call site.
50
+ *
51
+ * **The fallback is the whole reason this is two calls.** A browser that does not implement the
52
+ * option rejects with `NotSupportedError` and grants *nothing*, so asking once and giving up
53
+ * would trade an accelerated camera for no camera at all on every engine that lacks it. Asked
54
+ * again without the option, that browser behaves exactly as it did before this existed.
55
+ *
56
+ * **Firefox is that browser, measured on 2026-08-25, and the fallback is not a rescue there.**
57
+ * Firefox 154 returns a promise and rejects the option with `NotSupportedError`; asked plainly it
58
+ * accepts, and what it then delivers is the compositor's accelerated cursor travel in whole
59
+ * screen pixels — 1,787 locked events, **not one of them fractional**, 27% of them exactly one
60
+ * pixel, and a slow hand producing *no event at all* because the accelerated position never
61
+ * crosses a pixel boundary. That is the report this rule was written for, arriving again from a
62
+ * browser the rule cannot reach. Chromium honours the option and is unaffected.
63
+ *
64
+ * **So this function cannot fix Firefox and is not the place to try.** What it can do is what it
65
+ * does: ask properly, and fall back rather than leaving a game with no camera. A game that wants
66
+ * to respond — a warning, a different sensitivity — needs to be told, and nothing tells it yet.
67
+ * `demo/dev/mouse.html` is the instrument that produced the figures above.
68
+ */
69
+ const pending = request({ unadjustedMovement: true });
70
+ // Undefined on anything older than the promise, so this cannot reach for `.catch`
71
+ // unconditionally: a browser that merely lacks the feature would throw in a click.
72
+ if (pending === undefined) return;
73
+ void pending.catch((error: unknown) => {
74
+ /*
75
+ * **Only the option's own refusal is retried**, and the test is the name the specification
76
+ * gives it. Every other refusal is the ordinary one this function was written for — most
77
+ * often the second after the user left the lock with Escape, which is precisely when the
78
+ * next click arrives asking for it back — and asking again immediately would be a second
79
+ * request for the same denial rather than a fallback.
80
+ */
81
+ const unsupported =
82
+ typeof error === 'object' &&
83
+ error !== null &&
84
+ (error as { name?: string }).name === 'NotSupportedError';
85
+ if (!unsupported) return;
86
+ const plain = request();
87
+ if (plain !== undefined) {
88
+ void plain.catch(() => {
89
+ /* Refused. The game carries on with the mouse unlocked. */
90
+ });
91
+ }
92
+ });
93
+ }
94
+
95
+ export interface TouchPoint {
96
+ readonly id: number;
97
+ x: number;
98
+ y: number;
99
+ readonly startX: number;
100
+ readonly startY: number;
101
+ readonly startTime: number;
102
+ }
103
+
104
+ /** The devices this source watches, and the granularity a consumer may switch off. */
105
+ export type InputSourceName = 'keyboard' | 'mouse' | 'touch' | 'gamepad';
106
+
107
+ export interface InputOptions {
108
+ /**
109
+ * Turn a device off. Absent means on.
110
+ *
111
+ * A disabled source is **inert, not absent**: its state stops updating, it never takes the
112
+ * prompts, and — for the gamepad — the poll stops outright, so an application that does not want
113
+ * controllers pays for no snapshot at all.
114
+ */
115
+ readonly sources?: Partial<Record<InputSourceName, boolean>>;
116
+ /**
117
+ * Whether to poll the gamepad on an animation frame of this source's own. Defaults to true.
118
+ *
119
+ * **True is what makes support seamless**: a consumer that wired nothing still gets a working
120
+ * controller. Pass `false` and call `poll()` where you want the sample taken — which is what a
121
+ * recorded replay needs, since a sample pinned to the fixed tick is reproducible and one taken
122
+ * on a frame callback is not.
123
+ */
124
+ readonly autoPoll?: boolean;
125
+ /** How far a stick travels before it is moving. See `DEFAULT_DEADZONE`. */
126
+ readonly deadzone?: number;
127
+ }
128
+
129
+ /** What a pad is, as opposed to where its buttons are. See `gamepadIdentity.ts`. */
130
+ export interface GamepadIdentity {
131
+ readonly family: GamepadFamily;
132
+ /** What this pad calls that position: `faceDown` is `A`, `Cross` or `B`. */
133
+ label(button: GamepadButton): string;
134
+ /** A stable key for a consumer's own icon set, such as `xbox.a`. The engine ships no art. */
135
+ glyph(button: GamepadButton): string;
136
+ }
137
+
138
+ /**
139
+ * One connected pad, as a consumer holds it.
140
+ *
141
+ * A view per pad rather than flat accessors on the source, for two reasons: identity belongs to a
142
+ * device and would otherwise be passed alongside every call, and local multiplayer falls out of it
143
+ * instead of needing a second design later.
144
+ */
145
+ export interface GamepadView {
146
+ /** The browser's own slot, so a consumer can keep a player on the pad they picked up. */
147
+ readonly index: number;
148
+ readonly identity: GamepadIdentity;
149
+ /**
150
+ * `'standard'` when the browser vouches for the layout, `'unknown'` when it will not.
151
+ *
152
+ * The named accessors still answer on an unknown pad — they read the standard indices — but they
153
+ * are reading a guess, and this is how a consumer can tell.
154
+ */
155
+ readonly mapping: 'standard' | 'unknown';
156
+ /** Held right now. */
157
+ down(button: GamepadButton): boolean;
158
+ /**
159
+ * Went down since the last poll, readable by anything.
160
+ *
161
+ * Clears at the next poll rather than at the read, so a menu and a heads-up display may both see
162
+ * one press. Use `consumePress` where acting twice would be a bug.
163
+ */
164
+ pressed(button: GamepadButton): boolean;
165
+ /**
166
+ * The same edge, claimed — true for exactly one caller, then gone for everybody.
167
+ *
168
+ * **The hazard is a slow frame.** The fixed-step loop runs more than once, and a `pressed` that
169
+ * stayed true across both ticks is a double jump from a single press. Anything acting inside
170
+ * `simulate` claims; anything drawing reads `pressed`.
171
+ */
172
+ consumePress(button: GamepadButton): boolean;
173
+ /** A stick axis with the deadzone applied, in [-1, 1]. Vertical points **up at −1**. */
174
+ axis(axis: GamepadAxis): number;
175
+ /** A lower shoulder's analog travel, in [0, 1]. It is a button and an axis, honestly both. */
176
+ trigger(button: 'l2' | 'r2'): number;
177
+ /** Any button by raw index, for a pad whose layout the browser will not vouch for. */
178
+ button(index: number): boolean;
179
+ /** Any axis by raw index, untouched by the deadzone. */
180
+ rawAxis(index: number): number;
181
+ /**
182
+ * Whether this pad has motors this browser can drive.
183
+ *
184
+ * **Read it and grey the control out.** Most pads on most browsers cannot rumble, and a settings
185
+ * screen offering a slider the player's hardware ignores is worse than one that says so. Re-read
186
+ * it after a poll rather than caching: a pad unplugged and plugged back in is a different device
187
+ * behind the same slot.
188
+ */
189
+ readonly canRumble: boolean;
190
+ /**
191
+ * Play a rumble for `durationMs`, at two magnitudes in [0, 1]. Answers whether it was taken.
192
+ *
193
+ * `strong` is the low-frequency motor and `weak` the high-frequency one, which is what a standard
194
+ * pad has two of. Magnitudes are clamped into range and a duration past the platform's ceiling of
195
+ * five seconds is clamped to it; a duration at or below zero is nothing to play and answers
196
+ * `false`.
197
+ *
198
+ * **`false` is a real answer and not an error**: no actuator, a browser that cannot drive one, or
199
+ * nothing to play. It never throws, and a failure after the fact — the pad unplugged mid-effect —
200
+ * is reported once per pad on the console rather than as an unhandled rejection.
201
+ */
202
+ rumble(durationMs: number, strong: number, weak: number): boolean;
203
+ /** Stop whatever is playing. Answers whether the platform took it. */
204
+ stopRumble(): boolean;
205
+ }
206
+
207
+ export interface InputCallbacks {
208
+ onKeyDown?: (code: string) => void;
209
+ onTouchStart?: (touch: TouchPoint) => void;
210
+ onTouchMove?: (touch: TouchPoint) => void;
211
+ onTouchEnd?: (touch: TouchPoint, durationMs: number) => void;
212
+ }
213
+
214
+ /** Scratch for the deadzone, at module scope because `axis` is a per-frame read. */
215
+ const deadzoned = { x: 0, y: 0 };
216
+
217
+ /** Four is past generous for local play, and the array is preallocated to it. */
218
+ const MAX_PADS = 4;
219
+
220
+ /** The shape read off a `Gamepad`, named so this file does not depend on lib.dom's version. */
221
+ interface RawPad {
222
+ readonly id: string;
223
+ readonly index: number;
224
+ readonly mapping: string;
225
+ readonly buttons: ArrayLike<{ readonly pressed: boolean; readonly value: number }>;
226
+ readonly axes: ArrayLike<number>;
227
+ /** Absent on every pad without motors, and on every browser that does not implement them. */
228
+ readonly vibrationActuator?: RawHapticActuator | null;
229
+ }
230
+
231
+ /**
232
+ * One pad's state, reused across polls.
233
+ *
234
+ * **Bitmasks rather than arrays of booleans**, because the edge is the difference of two of them
235
+ * and seventeen buttons fit in one integer. `pressed` is `downNow & ~downLast`, computed once at
236
+ * the poll rather than derived at every read.
237
+ */
238
+ class PadState implements GamepadView {
239
+ index = -1;
240
+ mapping: 'standard' | 'unknown' = 'unknown';
241
+ live = false;
242
+ id = '';
243
+ private downNow = 0;
244
+ private downLast = 0;
245
+ private claimed = 0;
246
+ /**
247
+ * Presses waiting for somebody to act on them, one bit a button.
248
+ *
249
+ * The pad's half of the pair `keysUnclaimed` is for the keyboard, and it exists for the same
250
+ * reason: a claimant does not run every display frame. See `sync`.
251
+ */
252
+ private unclaimed = 0;
253
+ private readonly values = new Float32Array(17);
254
+ private readonly axes = new Float32Array(8);
255
+ private axisCount = 0;
256
+ private buttonCount = 0;
257
+ /**
258
+ * The actuator from the most recent poll, and it is re-read every poll on purpose.
259
+ *
260
+ * A `Gamepad` is a fresh snapshot each `getGamepads` call and a pad unplugged and plugged back in
261
+ * is a different device behind the same slot — holding the first actuator would drive hardware
262
+ * that is no longer there, or fail against one that is.
263
+ */
264
+ private actuator: RawHapticActuator | null = null;
265
+ /** So a failure is reported once per pad rather than once per effect. See `refuseIfUnvouched`. */
266
+ private rumbleFailed = false;
267
+ private readonly reportRumbleFailure = (): void => {
268
+ if (this.rumbleFailed) return;
269
+ this.rumbleFailed = true;
270
+ console.warn(
271
+ `[driftengine] this pad stopped taking haptic effects: ${JSON.stringify(this.id)}. ` +
272
+ 'It was most likely unplugged mid-effect; `canRumble` answers again after the next poll.',
273
+ );
274
+ };
275
+
276
+ private readonly identityObject = {
277
+ family: 'generic' as GamepadFamily,
278
+ label: (button: GamepadButton): string => labelFor(this.identityObject.family, button),
279
+ glyph: (button: GamepadButton): string => glyphFor(this.identityObject.family, button),
280
+ };
281
+
282
+ get identity(): GamepadIdentity {
283
+ return this.identityObject;
284
+ }
285
+
286
+ /** Copy a snapshot into numbers, and latch this frame's edges. Allocates nothing. */
287
+ sync(pad: RawPad): boolean {
288
+ if (pad.id !== this.id) {
289
+ this.id = pad.id;
290
+ this.identityObject.family = identifyGamepad(pad.id);
291
+ /* The browser's own word, normalised: it writes `''` where it will not vouch for a layout. */
292
+ this.mapping = pad.mapping === 'standard' ? 'standard' : 'unknown';
293
+ }
294
+ this.index = pad.index;
295
+ this.actuator = pad.vibrationActuator ?? null;
296
+ this.downLast = this.downNow;
297
+ let next = 0;
298
+ const buttons = Math.min(pad.buttons.length, 17);
299
+ this.buttonCount = buttons;
300
+ for (let i = 0; i < buttons; i += 1) {
301
+ const button = pad.buttons[i];
302
+ if (button === undefined) continue;
303
+ this.values[i] = button.value;
304
+ if (button.pressed) next |= 1 << i;
305
+ }
306
+ /*
307
+ * **A press waits to be claimed; only a release spends it.**
308
+ *
309
+ * This used to read *"an edge nobody claimed last frame is not carried into this one"*, which
310
+ * makes a press live for exactly one poll — and `poll` is on an animation frame while a
311
+ * fixed-step consumer is not. At 120 Hz against a 60 Hz simulation about half the display
312
+ * frames run no tick at all, so a press landing in one of those was dropped before anything
313
+ * could claim it, and a controller's jump went missing in proportion to the player's refresh
314
+ * rate. The keyboard was given a claim-scoped edge for this exact reason; the pad kept the
315
+ * frame-scoped one and had the same bug for longer.
316
+ *
317
+ * New presses accumulate, a claim spends one, and a button coming back up spends whatever is
318
+ * left — a press nobody wanted, whose button is no longer down, describes nothing anybody can
319
+ * still act on. Per button, so claiming one never spends another: two buttons in one frame are
320
+ * two independent claims, which is what *"press B+A at the same identical time"* needs.
321
+ */
322
+ this.unclaimed |= next & ~this.downNow;
323
+ this.unclaimed &= next;
324
+ this.downNow = next;
325
+ /* The *readable* edge stays frame-scoped: `pressed` is what a UI draws with, and a highlight
326
+ that outlived its frame would be wrong. */
327
+ this.claimed = 0;
328
+ const axes = Math.min(pad.axes.length, 8);
329
+ this.axisCount = axes;
330
+ for (let i = 0; i < axes; i += 1) this.axes[i] = pad.axes[i] ?? 0;
331
+ return next !== 0;
332
+ }
333
+
334
+ /** Whether any stick has left the dead region, which counts as the player using this pad. */
335
+ moved(deadzone: number): boolean {
336
+ for (let i = 0; i + 1 < this.axisCount; i += 2) {
337
+ applyDeadzone(this.axes[i] ?? 0, this.axes[i + 1] ?? 0, deadzone, deadzoned);
338
+ if (deadzoned.x !== 0 || deadzoned.y !== 0) return true;
339
+ }
340
+ return false;
341
+ }
342
+
343
+ deadzone = DEFAULT_DEADZONE;
344
+
345
+ down(button: GamepadButton): boolean {
346
+ return (this.downNow & (1 << BUTTON_INDEX[button])) !== 0;
347
+ }
348
+
349
+ pressed(button: GamepadButton): boolean {
350
+ const bit = 1 << BUTTON_INDEX[button];
351
+ return (this.downNow & ~this.downLast & ~this.claimed & bit) !== 0;
352
+ }
353
+
354
+ consumePress(button: GamepadButton): boolean {
355
+ const bit = 1 << BUTTON_INDEX[button];
356
+ if ((this.unclaimed & bit) === 0) return false;
357
+ this.unclaimed &= ~bit;
358
+ /* So the readable edge agrees within the frame that produced it: something drawing this button
359
+ as freshly pressed must stop the moment somebody acts on it. */
360
+ this.claimed |= bit;
361
+ return true;
362
+ }
363
+
364
+ axis(axis: GamepadAxis): number {
365
+ const index = AXIS_INDEX[axis];
366
+ /* Deadzoned against its partner, because the dead region is a circle over the pair rather
367
+ than a window on each — see `applyDeadzone`. */
368
+ const pairFirst = index - (index % 2);
369
+ applyDeadzone(
370
+ this.axes[pairFirst] ?? 0,
371
+ this.axes[pairFirst + 1] ?? 0,
372
+ this.deadzone,
373
+ deadzoned,
374
+ );
375
+ return index === pairFirst ? deadzoned.x : deadzoned.y;
376
+ }
377
+
378
+ /**
379
+ * A trigger's travel, and it is deliberately not `axis`.
380
+ *
381
+ * A stick's deadzone is a circle over a *pair*, and a trigger has no partner to pair with — so
382
+ * asking for one through `axis` would either invent a partner or mean something different from
383
+ * every other member of that method. It rests at 0 and needs no dead region of its own.
384
+ */
385
+ trigger(button: 'l2' | 'r2'): number {
386
+ return this.values[BUTTON_INDEX[button]] ?? 0;
387
+ }
388
+
389
+ button(index: number): boolean {
390
+ if (index < 0 || index >= this.buttonCount) return false;
391
+ return (this.downNow & (1 << index)) !== 0;
392
+ }
393
+
394
+ rawAxis(index: number): number {
395
+ if (index < 0 || index >= this.axisCount) return 0;
396
+ return this.axes[index] ?? 0;
397
+ }
398
+
399
+ get canRumble(): boolean {
400
+ return this.actuator !== null && typeof this.actuator.playEffect === 'function';
401
+ }
402
+
403
+ rumble(durationMs: number, strong: number, weak: number): boolean {
404
+ return playRumble(this.actuator, durationMs, strong, weak, this.reportRumbleFailure);
405
+ }
406
+
407
+ stopRumble(): boolean {
408
+ return stopRumble(this.actuator, this.reportRumbleFailure);
409
+ }
410
+ }
411
+
412
+ export class InputSource {
413
+ readonly isCoarse: boolean;
414
+ readonly touches = new Map<number, TouchPoint>();
415
+ readonly target: HTMLElement;
416
+
417
+ private readonly keys = new Set<string>();
418
+ private readonly preventDefaultCodes: ReadonlySet<string>;
419
+ private readonly subscribers: InputCallbacks[] = [];
420
+ private mouseDx = 0;
421
+ private mouseDy = 0;
422
+ private mouseButtonDown = false;
423
+ private readonly disposers: Array<() => void> = [];
424
+
425
+ /** Which device the player last actually used, and who wants telling when that changes. */
426
+ private readonly active = new ActiveDevice();
427
+ private readonly enabled: Record<InputSourceName, boolean> = {
428
+ keyboard: true,
429
+ mouse: true,
430
+ touch: true,
431
+ gamepad: true,
432
+ };
433
+ /** Preallocated: a poll must not build a pad per frame. */
434
+ private readonly padStates: PadState[] = Array.from({ length: MAX_PADS }, () => new PadState());
435
+ /** The live subset, as a stable array whose length is set rather than rebuilt. */
436
+ private readonly padViews: GamepadView[] = [];
437
+ private deadzone = DEFAULT_DEADZONE;
438
+ private autoPoll = true;
439
+ private frameHandle = 0;
440
+ /** Devices already refused in words, so a refusal is once a pad rather than once a frame. */
441
+ private readonly refusedPads = new Set<string>();
442
+ /**
443
+ * Keys that went down since the last poll, and the ones a caller has claimed.
444
+ *
445
+ * `isDown` is a level and `onKeyDown` is a callback; neither is an edge a simulation tick can
446
+ * take. These give the keyboard the two verbs a pad already had, latched at the same moment and
447
+ * cleared at the same one, which is what lets one action answer for both devices without either
448
+ * being a special case.
449
+ */
450
+ private keysPressed = new Set<string>();
451
+ private keysPressedNext = new Set<string>();
452
+ private readonly keysClaimed = new Set<string>();
453
+ /**
454
+ * Presses waiting for somebody to act on them.
455
+ *
456
+ * **Separate from `keysPressed`, because the two edges have different lifetimes and conflating
457
+ * them lost inputs.** `keysPressed` is for *drawing* — a highlight that outlived its frame would
458
+ * be wrong — so it rotates every poll. This one is for *acting*, and a claimant does not run
459
+ * every frame: `poll` is on an animation frame and a fixed-step simulation is not, so at 120 Hz
460
+ * against a 60 Hz tick about half the display frames run no tick at all. A press that landed in
461
+ * one of those was rotated away before anything could claim it, and the player's jump did not
462
+ * happen — intermittently, in proportion to their refresh rate. A consumer found it by replacing
463
+ * a hand-rolled `onKeyDown` latch, which cleared only when the simulation ran, with
464
+ * `ActionMap.consumePress`.
465
+ *
466
+ * So a claim lives until it is claimed or until the key comes back up. **Releasing is what makes
467
+ * it stale**: a press nobody wanted, whose key is no longer down, describes nothing anybody can
468
+ * still act on. What this costs is a press held across a screen that does not read it, which
469
+ * then lands on the screen that does — which is the same thing the hand-rolled latch did.
470
+ */
471
+ private readonly keysUnclaimed = new Set<string>();
472
+
473
+ /**
474
+ * `options` is a **third** parameter rather than a widened second, so every existing call site
475
+ * keeps compiling. A consumer that passes only a target and its prevent-default codes gets the
476
+ * behaviour it always had, plus a working controller it did not ask for.
477
+ */
478
+ constructor(
479
+ target: HTMLElement,
480
+ preventDefaultCodes: Iterable<string> = [],
481
+ options: InputOptions = {},
482
+ ) {
483
+ this.target = target;
484
+ this.preventDefaultCodes = new Set(preventDefaultCodes);
485
+ this.isCoarse = window.matchMedia('(pointer: coarse)').matches;
486
+ this.deadzone = options.deadzone ?? DEFAULT_DEADZONE;
487
+ this.autoPoll = options.autoPoll ?? true;
488
+ for (const name of ['keyboard', 'mouse', 'touch', 'gamepad'] as const) {
489
+ this.enabled[name] = options.sources?.[name] ?? true;
490
+ }
491
+ for (const pad of this.padStates) pad.deadzone = this.deadzone;
492
+
493
+ this.listen(window, 'keydown', (e: KeyboardEvent) => {
494
+ /*
495
+ * A keystroke aimed at a text field is not the game's.
496
+ *
497
+ * Before this, `preventDefaultCodes` applied everywhere, so a consumer that
498
+ * asked for `Space` and `KeyE` — reasonably, since Space scrolls the page —
499
+ * silently made those characters untypeable in its own forms. A consumer
500
+ * hit exactly that: a player could not put a space or an `e` into a bug report.
501
+ *
502
+ * The key is not registered either, not merely un-prevented: holding `W` to
503
+ * write a word must not walk the character into the sea behind the dialog.
504
+ */
505
+ if (isTypingTarget(e.target)) return;
506
+ if (!this.enabled.keyboard) return;
507
+ if (this.preventDefaultCodes.has(e.code)) e.preventDefault();
508
+ if (e.repeat) return;
509
+ this.keys.add(e.code);
510
+ this.keysPressedNext.add(e.code);
511
+ this.keysUnclaimed.add(e.code);
512
+ this.active.use('keyboard');
513
+ for (let i = 0; i < this.subscribers.length; i++) {
514
+ this.subscribers[i]?.onKeyDown?.(e.code);
515
+ }
516
+ });
517
+ // Always released, even from a field: a key held *before* focus moved into one
518
+ // is in `keys`, and skipping its keyup would leave the character walking forever.
519
+ this.listen(window, 'keyup', (e: KeyboardEvent) => {
520
+ this.keys.delete(e.code);
521
+ /* And the unclaimed press goes with it — see `keysUnclaimed`. */
522
+ this.keysUnclaimed.delete(e.code);
523
+ });
524
+ this.listen(window, 'blur', () => {
525
+ this.keys.clear();
526
+ this.keysUnclaimed.clear();
527
+ });
528
+
529
+ this.listen(target, 'mousedown', () => {
530
+ if (!this.enabled.mouse) return;
531
+ this.mouseButtonDown = true;
532
+ this.active.use('mouse');
533
+ });
534
+ this.listen(window, 'mouseup', () => {
535
+ this.mouseButtonDown = false;
536
+ });
537
+ /*
538
+ * **Released by anything that can eat the mouseup, exactly as the keys are.**
539
+ *
540
+ * A held key survives a lost focus and leaves the character walking forever, which is why
541
+ * `blur` clears `keys` above. This flag had no such release and is worse when it sticks,
542
+ * because it does not merely hold an input on — it silently moves the look onto a **cursor
543
+ * that is not locked**, and an unlocked cursor is a different device: its `movementX` is the
544
+ * travel of an arrow across the desktop, so it stops dead at the edge of the display and it
545
+ * arrives in whole screen pixels with the operating system's acceleration curve on it.
546
+ *
547
+ * That is two bug reports in one. The camera turns until it will not turn any further and
548
+ * only frees up when the mouse is moved back, which is the arrow sitting against the edge;
549
+ * and a slow hand moves the camera not at all while a fast one moves it in steps, which is
550
+ * sub-pixel travel rounding to zero and then to several at once. Both were reported on
551
+ * browser fullscreen, where the transition blurs the window — eating the mouseup — and the
552
+ * frame is the whole screen, so there is no desktop left to travel across before the edge.
553
+ *
554
+ * `visibilitychange` as well as `blur`, because a tab switched away with a button held
555
+ * comes back to a document that never saw the release either.
556
+ */
557
+ this.listen(window, 'blur', () => {
558
+ this.mouseButtonDown = false;
559
+ });
560
+ this.listen(window, 'pointercancel', () => {
561
+ this.mouseButtonDown = false;
562
+ });
563
+ /* Not in `GlobalEventHandlersEventMap`, so it is bound directly and disposed by hand. */
564
+ const onHidden = (): void => {
565
+ if (document.visibilityState !== 'visible') this.mouseButtonDown = false;
566
+ };
567
+ document.addEventListener('visibilitychange', onHidden);
568
+ this.disposers.push(() => document.removeEventListener('visibilitychange', onHidden));
569
+ this.listen(window, 'mousemove', (e: MouseEvent) => {
570
+ if (!this.enabled.mouse) return;
571
+ /* Offered rather than asserted: a mousemove is not necessarily a decision, so
572
+ `ActiveDevice` accumulates it against a threshold. See its own comment. */
573
+ this.active.moved(e.movementX, e.movementY);
574
+ if (this.hasPointerLock || this.mouseButtonDown) {
575
+ this.mouseDx += e.movementX;
576
+ this.mouseDy += e.movementY;
577
+ }
578
+ });
579
+
580
+ this.listen(target, 'touchstart', (e: TouchEvent) => this.onTouches(e, 'start'), false);
581
+ this.listen(target, 'touchmove', (e: TouchEvent) => this.onTouches(e, 'move'), false);
582
+ this.listen(target, 'touchend', (e: TouchEvent) => this.onTouches(e, 'end'), false);
583
+ this.listen(target, 'touchcancel', (e: TouchEvent) => this.onTouches(e, 'end'), false);
584
+
585
+ /* **This is what makes a controller work with no wiring at all**, which is the requirement.
586
+ It never starts when the source is off, so an application that declines controllers pays
587
+ nothing rather than paying for a loop that returns immediately. */
588
+ this.startPolling();
589
+ }
590
+
591
+ isDown(code: string): boolean {
592
+ return this.keys.has(code);
593
+ }
594
+
595
+ /* -- Gamepads, hints and policy -------------------------------------------------------- */
596
+
597
+ /**
598
+ * The pads currently connected and seen, most recently sampled.
599
+ *
600
+ * **A pad is invisible until the player uses it**, and that is the browser's rule rather than
601
+ * this engine's: reporting a connected gamepad before a button has been pressed is a
602
+ * fingerprinting surface, so none does. It happens to be the rule this design wanted anyway.
603
+ *
604
+ * The array is stable and its length is set rather than rebuilt, so reading it allocates
605
+ * nothing.
606
+ */
607
+ get pads(): readonly GamepadView[] {
608
+ return this.padViews;
609
+ }
610
+
611
+ /**
612
+ * One pad by position in `pads`, or null.
613
+ *
614
+ * **Position in the list, not the browser's slot** — `GamepadView.index` answers that, and is
615
+ * what a consumer pins a player to. The distinction shows itself when a pad is unplugged: the
616
+ * list closes up, and a caller holding a slot wants `index`.
617
+ */
618
+ pad(at: number): GamepadView | null {
619
+ return this.padViews[at] ?? null;
620
+ }
621
+
622
+ /** Which device the player last actually used. See `activeDevice.ts` for what counts as use. */
623
+ get lastDevice(): InputDevice {
624
+ return this.active.last;
625
+ }
626
+
627
+ /** Told when that changes, and only when it changes. Returns the unsubscribe. */
628
+ onDeviceChange(listener: (device: InputDevice) => void): () => void {
629
+ return this.active.subscribe(listener);
630
+ }
631
+
632
+ /**
633
+ * Turn a device on or off at runtime, for a settings screen.
634
+ *
635
+ * A disabled source is inert rather than absent, and disabling the gamepad stops the poll
636
+ * outright — so an application that does not want controllers pays for no snapshot a frame.
637
+ */
638
+ setSourceEnabled(source: InputSourceName, enabled: boolean): void {
639
+ this.enabled[source] = enabled;
640
+ if (source !== 'gamepad') return;
641
+ if (enabled) {
642
+ this.startPolling();
643
+ return;
644
+ }
645
+ this.padViews.length = 0;
646
+ }
647
+
648
+ /**
649
+ * Sample the pads now.
650
+ *
651
+ * **Called once an animation frame by this source's own loop unless `autoPoll` is false**, and
652
+ * public so a consumer can pin the sample to its own fixed tick instead — which is what a
653
+ * recorded replay needs, since a sample taken on a frame callback is not reproducible.
654
+ *
655
+ * **`getGamepads()` allocates**, an array and the objects behind it, and that cost is the
656
+ * browser's rather than something this engine can pool. So it is called exactly once here and
657
+ * never from a read: every accessor on a view is a lookup on numbers already copied out. A frame
658
+ * that runs three simulation ticks polls once, which is also the correct semantics — the
659
+ * hardware cannot have changed between two ticks of one frame.
660
+ */
661
+ poll(): void {
662
+ /*
663
+ * The keyboard's frame boundary, and it happens whether or not there are pads.
664
+ *
665
+ * Rotated rather than cleared: a key pressed *during* the frame that is about to end belongs
666
+ * to the next one, and clearing here would drop it on any consumer that presses and polls in
667
+ * the same task. The two sets are swapped so neither is allocated per frame.
668
+ */
669
+ const spent = this.keysPressed;
670
+ this.keysPressed = this.keysPressedNext;
671
+ spent.clear();
672
+ this.keysPressedNext = spent;
673
+ this.keysClaimed.clear();
674
+
675
+ if (!this.enabled.gamepad) return;
676
+ const source = (globalThis as { navigator?: { getGamepads?: () => (RawPad | null)[] } })
677
+ .navigator;
678
+ if (source === undefined || typeof source.getGamepads !== 'function') return;
679
+
680
+ const raw = source.getGamepads();
681
+ let live = 0;
682
+ let used = false;
683
+ for (let i = 0; i < raw.length && live < MAX_PADS; i += 1) {
684
+ const pad = raw[i];
685
+ if (pad === null || pad === undefined) continue;
686
+ const state = this.padStates[live];
687
+ if (state === undefined) continue;
688
+
689
+ const anyDown = state.sync(pad);
690
+ this.refuseIfUnvouched(state);
691
+ if (anyDown || state.moved(this.deadzone)) used = true;
692
+ this.padViews[live] = state;
693
+ live += 1;
694
+ }
695
+ this.padViews.length = live;
696
+ if (used) this.active.use('gamepad');
697
+ }
698
+
699
+ /**
700
+ * Say once, per device, that a pad's layout is not one the browser will vouch for.
701
+ *
702
+ * **Served rather than refused**, so a consumer that knows the device can still reach it by
703
+ * index — but said out loud, because silence would leave a player whose arcade stick does
704
+ * nothing with no way to discover why, which is the silent no-op the house rules forbid. Once
705
+ * per device rather than once per frame, exactly as `registerCompute` refuses: a line every
706
+ * frame floods a console somebody needs to read.
707
+ */
708
+ private refuseIfUnvouched(state: PadState): void {
709
+ if (state.mapping !== 'unknown' || this.refusedPads.has(state.id)) return;
710
+ this.refusedPads.add(state.id);
711
+ console.warn(
712
+ `[driftengine] the browser will not vouch for this pad's layout: ${JSON.stringify(state.id)}. ` +
713
+ 'Its named buttons read the standard positions and may be wrong; read `mapping` and reach ' +
714
+ 'it with `button(index)` and `rawAxis(index)`.',
715
+ );
716
+ }
717
+
718
+ private startPolling(): void {
719
+ /*
720
+ * Not gated on the gamepad source, and that changed in 2.13.0. The poll advances the *input*
721
+ * frame — it rotates the keyboard's edges as well as sampling pads — so a consumer that
722
+ * switched controllers off would otherwise find `keyPressed` never clearing. What the gamepad
723
+ * switch still turns off is the expensive half: `getGamepads`, which allocates, is not called
724
+ * at all.
725
+ */
726
+ if (this.frameHandle !== 0 || !this.autoPoll) return;
727
+ const frames = (globalThis as { requestAnimationFrame?: (fn: () => void) => number })
728
+ .requestAnimationFrame;
729
+ if (typeof frames !== 'function') return;
730
+ /* Built once rather than per frame: a closure created every frame is the allocation the house
731
+ rule about hot paths is about. */
732
+ const tick = (): void => {
733
+ this.frameHandle = frames(tick);
734
+ this.poll();
735
+ };
736
+ this.frameHandle = frames(tick);
737
+ }
738
+
739
+ private stopPolling(): void {
740
+ if (this.frameHandle === 0) return;
741
+ const cancel = (globalThis as { cancelAnimationFrame?: (handle: number) => void })
742
+ .cancelAnimationFrame;
743
+ if (typeof cancel === 'function') cancel(this.frameHandle);
744
+ this.frameHandle = 0;
745
+ }
746
+
747
+ /**
748
+ * Whether a key went down since the last poll. Readable by anything, cleared at the next poll.
749
+ *
750
+ * The keyboard's half of the pair `GamepadView.pressed` documents: use this to draw, and
751
+ * `consumeKeyPress` to act, so a slow frame running the fixed-step loop twice cannot act twice.
752
+ */
753
+ keyPressed(code: string): boolean {
754
+ return this.keysPressed.has(code) && !this.keysClaimed.has(code);
755
+ }
756
+
757
+ /** The same edge, claimed: true for exactly one caller, then gone for everybody. */
758
+ consumeKeyPress(code: string): boolean {
759
+ if (!this.keysUnclaimed.delete(code)) return false;
760
+ /* So the readable edge agrees within the frame that produced it: something drawing this key as
761
+ freshly pressed must stop the moment somebody acts on it. */
762
+ this.keysClaimed.add(code);
763
+ return true;
764
+ }
765
+
766
+ /**
767
+ * Add a device-event subscriber. Multiple reusable control layers may listen
768
+ * without overwriting one another; interpretation still happens outside the
769
+ * raw source. Subscription and removal are initialization-time operations.
770
+ */
771
+ subscribe(callbacks: InputCallbacks): () => void {
772
+ this.subscribers.push(callbacks);
773
+ let subscribed = true;
774
+ return () => {
775
+ if (!subscribed) return;
776
+ subscribed = false;
777
+ const index = this.subscribers.indexOf(callbacks);
778
+ if (index >= 0) this.subscribers.splice(index, 1);
779
+ };
780
+ }
781
+
782
+ /** Drain accumulated relative mouse motion into `out` (allocation-free). */
783
+ consumeMouseDelta(out: { dx: number; dy: number }): void {
784
+ out.dx = this.mouseDx;
785
+ out.dy = this.mouseDy;
786
+ this.mouseDx = 0;
787
+ this.mouseDy = 0;
788
+ }
789
+
790
+ get hasPointerLock(): boolean {
791
+ return document.pointerLockElement === this.target;
792
+ }
793
+
794
+ requestPointerLock(): void {
795
+ if (!this.isCoarse && !this.hasPointerLock) {
796
+ /*
797
+ * **The options are forwarded, and this line is where they were lost.**
798
+ *
799
+ * It was `() => this.target.requestPointerLock()`, a lambda taking no parameters, so the
800
+ * `{ unadjustedMovement: true }` that `askForPointerLock` builds was passed to it and
801
+ * dropped. Every browser was asked plainly, the fallback had nothing to fall back from, and
802
+ * the camera kept the desktop's acceleration curve for as long as the feature had shipped —
803
+ * reported twice from Firefox and from two separate consumers, which is what said it was the
804
+ * engine rather than one application's wiring. `input.test.ts` covered the helper and not
805
+ * this call, which is why three green tests sat on top of it.
806
+ */
807
+ askForPointerLock((options) => this.target.requestPointerLock(options));
808
+ }
809
+ }
810
+
811
+ dispose(): void {
812
+ this.stopPolling();
813
+ this.padViews.length = 0;
814
+ for (const dispose of this.disposers) dispose();
815
+ this.disposers.length = 0;
816
+ this.subscribers.length = 0;
817
+ this.keys.clear();
818
+ this.touches.clear();
819
+ }
820
+
821
+ private onTouches(e: TouchEvent, phase: 'start' | 'move' | 'end'): void {
822
+ if (!this.enabled.touch) return;
823
+ e.preventDefault();
824
+ if (phase === 'start') this.active.use('touch');
825
+ const now = performance.now();
826
+ for (let i = 0; i < e.changedTouches.length; i++) {
827
+ const t = e.changedTouches[i];
828
+ if (t === undefined) continue;
829
+ if (phase === 'start') {
830
+ const point: TouchPoint = {
831
+ id: t.identifier,
832
+ x: t.clientX,
833
+ y: t.clientY,
834
+ startX: t.clientX,
835
+ startY: t.clientY,
836
+ startTime: now,
837
+ };
838
+ this.touches.set(t.identifier, point);
839
+ for (let subscriber = 0; subscriber < this.subscribers.length; subscriber++) {
840
+ this.subscribers[subscriber]?.onTouchStart?.(point);
841
+ }
842
+ } else {
843
+ const point = this.touches.get(t.identifier);
844
+ if (point === undefined) continue;
845
+ point.x = t.clientX;
846
+ point.y = t.clientY;
847
+ if (phase === 'move') {
848
+ for (let subscriber = 0; subscriber < this.subscribers.length; subscriber++) {
849
+ this.subscribers[subscriber]?.onTouchMove?.(point);
850
+ }
851
+ } else {
852
+ this.touches.delete(t.identifier);
853
+ const durationMs = now - point.startTime;
854
+ for (let subscriber = 0; subscriber < this.subscribers.length; subscriber++) {
855
+ this.subscribers[subscriber]?.onTouchEnd?.(point, durationMs);
856
+ }
857
+ }
858
+ }
859
+ }
860
+ }
861
+
862
+ private listen<K extends keyof GlobalEventHandlersEventMap>(
863
+ target: EventTarget,
864
+ type: K,
865
+ handler: (event: GlobalEventHandlersEventMap[K]) => void,
866
+ passive?: boolean,
867
+ ): void {
868
+ const options = passive === undefined ? undefined : { passive };
869
+ target.addEventListener(type, handler as EventListener, options);
870
+ this.disposers.push(() => target.removeEventListener(type, handler as EventListener));
871
+ }
872
+ }