rn-gamekit 0.1.0 → 0.2.1

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 (601) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +97 -16
  3. package/lib/module/assets/defineAssets.js +28 -3
  4. package/lib/module/assets/defineAssets.js.map +1 -1
  5. package/lib/module/assets.js +11 -0
  6. package/lib/module/assets.js.map +1 -0
  7. package/lib/module/audio/createGameAudio.js +784 -0
  8. package/lib/module/audio/createGameAudio.js.map +1 -0
  9. package/lib/module/audio/errors.js +12 -0
  10. package/lib/module/audio/errors.js.map +1 -0
  11. package/lib/module/audio/index.js +5 -0
  12. package/lib/module/audio/index.js.map +1 -0
  13. package/lib/module/audio/resolver.js +37 -0
  14. package/lib/module/audio/resolver.js.map +1 -0
  15. package/lib/module/audio/types.js +4 -0
  16. package/lib/module/audio/types.js.map +1 -0
  17. package/lib/module/audio.js +9 -0
  18. package/lib/module/audio.js.map +1 -0
  19. package/lib/module/camera2d/bounds.js +59 -0
  20. package/lib/module/camera2d/bounds.js.map +1 -0
  21. package/lib/module/camera2d/extents.js +25 -0
  22. package/lib/module/camera2d/extents.js.map +1 -0
  23. package/lib/module/camera2d/follow.js +138 -0
  24. package/lib/module/camera2d/follow.js.map +1 -0
  25. package/lib/module/camera2d/index.js +20 -0
  26. package/lib/module/camera2d/index.js.map +1 -0
  27. package/lib/module/camera2d/interpolation.js +98 -0
  28. package/lib/module/camera2d/interpolation.js.map +1 -0
  29. package/lib/module/camera2d/shake.js +85 -0
  30. package/lib/module/camera2d/shake.js.map +1 -0
  31. package/lib/module/camera2d/transform.js +151 -0
  32. package/lib/module/camera2d/transform.js.map +1 -0
  33. package/lib/module/camera2d/types.js +4 -0
  34. package/lib/module/camera2d/types.js.map +1 -0
  35. package/lib/module/camera2d/validation.js +98 -0
  36. package/lib/module/camera2d/validation.js.map +1 -0
  37. package/lib/module/camera2d/visibility.js +138 -0
  38. package/lib/module/camera2d/visibility.js.map +1 -0
  39. package/lib/module/camera2d.js +9 -0
  40. package/lib/module/camera2d.js.map +1 -0
  41. package/lib/module/collision2d/colliders.js +266 -0
  42. package/lib/module/collision2d/colliders.js.map +1 -0
  43. package/lib/module/collision2d/debug.js +105 -0
  44. package/lib/module/collision2d/debug.js.map +1 -0
  45. package/lib/module/collision2d/filters.js +40 -0
  46. package/lib/module/collision2d/filters.js.map +1 -0
  47. package/lib/module/collision2d/index.js +12 -0
  48. package/lib/module/collision2d/index.js.map +1 -0
  49. package/lib/module/collision2d/intersections.js +67 -0
  50. package/lib/module/collision2d/intersections.js.map +1 -0
  51. package/lib/module/collision2d/manifolds.js +218 -0
  52. package/lib/module/collision2d/manifolds.js.map +1 -0
  53. package/lib/module/collision2d/segments.js +187 -0
  54. package/lib/module/collision2d/segments.js.map +1 -0
  55. package/lib/module/collision2d/spatialHash.js +167 -0
  56. package/lib/module/collision2d/spatialHash.js.map +1 -0
  57. package/lib/module/collision2d/sweeps.js +255 -0
  58. package/lib/module/collision2d/sweeps.js.map +1 -0
  59. package/lib/module/collision2d.js +9 -0
  60. package/lib/module/collision2d.js.map +1 -0
  61. package/lib/module/core/input/buttonPad.js +214 -0
  62. package/lib/module/core/input/buttonPad.js.map +1 -0
  63. package/lib/module/core/input/createInputBuffer.js +66 -14
  64. package/lib/module/core/input/createInputBuffer.js.map +1 -1
  65. package/lib/module/core/session/createGameSession.js +454 -50
  66. package/lib/module/core/session/createGameSession.js.map +1 -1
  67. package/lib/module/core/session/deepFreeze.js +92 -2
  68. package/lib/module/core/session/deepFreeze.js.map +1 -1
  69. package/lib/module/core/session/types.js +12 -0
  70. package/lib/module/core/session/types.js.map +1 -1
  71. package/lib/module/definition/defineGame.js +23 -0
  72. package/lib/module/definition/defineGame.js.map +1 -1
  73. package/lib/module/events/defineGameEvents.js +46 -0
  74. package/lib/module/events/defineGameEvents.js.map +1 -0
  75. package/lib/module/events/errors.js +16 -0
  76. package/lib/module/events/errors.js.map +1 -0
  77. package/lib/module/events/index.js +7 -0
  78. package/lib/module/events/index.js.map +1 -0
  79. package/lib/module/events/payload.js +219 -0
  80. package/lib/module/events/payload.js.map +1 -0
  81. package/lib/module/events/seed.js +33 -0
  82. package/lib/module/events/seed.js.map +1 -0
  83. package/lib/module/events/types.js +4 -0
  84. package/lib/module/events/types.js.map +1 -0
  85. package/lib/module/events.js +13 -0
  86. package/lib/module/events.js.map +1 -0
  87. package/lib/module/geometry/helpers.js +140 -0
  88. package/lib/module/geometry/helpers.js.map +1 -0
  89. package/lib/module/geometry/index.js +5 -0
  90. package/lib/module/geometry/index.js.map +1 -0
  91. package/lib/module/geometry/validation.js +104 -0
  92. package/lib/module/geometry/validation.js.map +1 -0
  93. package/lib/module/geometry.js +9 -0
  94. package/lib/module/geometry.js.map +1 -0
  95. package/lib/module/haptics/createGameHaptics.js +214 -0
  96. package/lib/module/haptics/createGameHaptics.js.map +1 -0
  97. package/lib/module/haptics/errors.js +12 -0
  98. package/lib/module/haptics/errors.js.map +1 -0
  99. package/lib/module/haptics/index.js +5 -0
  100. package/lib/module/haptics/index.js.map +1 -0
  101. package/lib/module/haptics/resolver.js +37 -0
  102. package/lib/module/haptics/resolver.js.map +1 -0
  103. package/lib/module/haptics/types.js +4 -0
  104. package/lib/module/haptics/types.js.map +1 -0
  105. package/lib/module/haptics.js +9 -0
  106. package/lib/module/haptics.js.map +1 -0
  107. package/lib/module/index.js +8 -1
  108. package/lib/module/index.js.map +1 -1
  109. package/lib/module/particles/createParticleSystem.js +481 -0
  110. package/lib/module/particles/createParticleSystem.js.map +1 -0
  111. package/lib/module/particles/defineParticleEffect.js +178 -0
  112. package/lib/module/particles/defineParticleEffect.js.map +1 -0
  113. package/lib/module/particles/errors.js +9 -0
  114. package/lib/module/particles/errors.js.map +1 -0
  115. package/lib/module/particles/index.js +8 -0
  116. package/lib/module/particles/index.js.map +1 -0
  117. package/lib/module/particles/sampling.js +121 -0
  118. package/lib/module/particles/sampling.js.map +1 -0
  119. package/lib/module/particles/types.js +4 -0
  120. package/lib/module/particles/types.js.map +1 -0
  121. package/lib/module/particles.js +4 -0
  122. package/lib/module/particles.js.map +1 -0
  123. package/lib/module/react/GameButtonPad.js +344 -0
  124. package/lib/module/react/GameButtonPad.js.map +1 -0
  125. package/lib/module/react/GamePointerInput.js +74 -16
  126. package/lib/module/react/GamePointerInput.js.map +1 -1
  127. package/lib/module/react/GameView.js +139 -60
  128. package/lib/module/react/GameView.js.map +1 -1
  129. package/lib/module/react/assets/createGameAssetStore.js +145 -95
  130. package/lib/module/react/assets/createGameAssetStore.js.map +1 -1
  131. package/lib/module/react/assets/useGameAssets.js +60 -35
  132. package/lib/module/react/assets/useGameAssets.js.map +1 -1
  133. package/lib/module/react/bindAppLifecycle.js +46 -17
  134. package/lib/module/react/bindAppLifecycle.js.map +1 -1
  135. package/lib/module/react/bindGameSession.js +13 -2
  136. package/lib/module/react/bindGameSession.js.map +1 -1
  137. package/lib/module/react/camera2d/GameLayer2D.js +50 -0
  138. package/lib/module/react/camera2d/GameLayer2D.js.map +1 -0
  139. package/lib/module/react/camera2d/defineGameCamera2D.js +30 -0
  140. package/lib/module/react/camera2d/defineGameCamera2D.js.map +1 -0
  141. package/lib/module/react/camera2d/usePresentedCameraBinding.js +177 -0
  142. package/lib/module/react/camera2d/usePresentedCameraBinding.js.map +1 -0
  143. package/lib/module/react/cleanupList.js +38 -0
  144. package/lib/module/react/cleanupList.js.map +1 -0
  145. package/lib/module/react/lifecycleSource.js +49 -0
  146. package/lib/module/react/lifecycleSource.js.map +1 -0
  147. package/lib/module/react/particles/ParticleView.js +308 -0
  148. package/lib/module/react/particles/ParticleView.js.map +1 -0
  149. package/lib/module/react/particles/culling.js +115 -0
  150. package/lib/module/react/particles/culling.js.map +1 -0
  151. package/lib/module/react/particles/index.js +7 -0
  152. package/lib/module/react/particles/index.js.map +1 -0
  153. package/lib/module/react/particles/spriteXForm.js +45 -0
  154. package/lib/module/react/particles/spriteXForm.js.map +1 -0
  155. package/lib/module/react/particles/useParticlePresentation.js +204 -0
  156. package/lib/module/react/particles/useParticlePresentation.js.map +1 -0
  157. package/lib/module/react/pointerBinding.js +55 -17
  158. package/lib/module/react/pointerBinding.js.map +1 -1
  159. package/lib/module/react/pointerCamera.js +28 -0
  160. package/lib/module/react/pointerCamera.js.map +1 -0
  161. package/lib/module/react/pointerCoalescer.js +16 -9
  162. package/lib/module/react/pointerCoalescer.js.map +1 -1
  163. package/lib/module/react/sprites/GameSprite.js +5 -17
  164. package/lib/module/react/sprites/GameSprite.js.map +1 -1
  165. package/lib/module/react/sprites/GameWorld2D.js +112 -9
  166. package/lib/module/react/sprites/GameWorld2D.js.map +1 -1
  167. package/lib/module/react/sprites/Sprite.js +48 -63
  168. package/lib/module/react/sprites/Sprite.js.map +1 -1
  169. package/lib/module/react/sprites/SpriteBatch.js +53 -28
  170. package/lib/module/react/sprites/SpriteBatch.js.map +1 -1
  171. package/lib/module/react/sprites/batchVisibility.js +58 -0
  172. package/lib/module/react/sprites/batchVisibility.js.map +1 -0
  173. package/lib/module/react/sprites/spriteSelection.js +103 -0
  174. package/lib/module/react/sprites/spriteSelection.js.map +1 -0
  175. package/lib/module/react/sprites/spriteTransform.js +46 -25
  176. package/lib/module/react/sprites/spriteTransform.js.map +1 -1
  177. package/lib/module/react/tilemap/TileMapLayer2D.js +217 -0
  178. package/lib/module/react/tilemap/TileMapLayer2D.js.map +1 -0
  179. package/lib/module/react/tilemap/tilePresentation.js +374 -0
  180. package/lib/module/react/tilemap/tilePresentation.js.map +1 -0
  181. package/lib/module/react/useGameSession.js +70 -0
  182. package/lib/module/react/useGameSession.js.map +1 -0
  183. package/lib/module/react/useGameSessionStatus.js +46 -0
  184. package/lib/module/react/useGameSessionStatus.js.map +1 -0
  185. package/lib/module/react/viewportBinding.js +5 -1
  186. package/lib/module/react/viewportBinding.js.map +1 -1
  187. package/lib/module/react.js +12 -1
  188. package/lib/module/react.js.map +1 -1
  189. package/lib/module/scene/defineScene.js +17 -0
  190. package/lib/module/scene/defineScene.js.map +1 -1
  191. package/lib/module/sprites/sampleSpriteClip.js +66 -6
  192. package/lib/module/sprites/sampleSpriteClip.js.map +1 -1
  193. package/lib/module/sprites/spriteAnimationState.js +10 -20
  194. package/lib/module/sprites/spriteAnimationState.js.map +1 -1
  195. package/lib/module/sprites.js +11 -0
  196. package/lib/module/sprites.js.map +1 -0
  197. package/lib/module/storage/adapters/asyncStorage.js +57 -0
  198. package/lib/module/storage/adapters/asyncStorage.js.map +1 -0
  199. package/lib/module/storage/adapters/memory.js +50 -0
  200. package/lib/module/storage/adapters/memory.js.map +1 -0
  201. package/lib/module/storage/errors.js +34 -0
  202. package/lib/module/storage/errors.js.map +1 -0
  203. package/lib/module/storage/index.js +11 -0
  204. package/lib/module/storage/index.js.map +1 -0
  205. package/lib/module/storage/schema.js +151 -0
  206. package/lib/module/storage/schema.js.map +1 -0
  207. package/lib/module/storage/serialization.js +249 -0
  208. package/lib/module/storage/serialization.js.map +1 -0
  209. package/lib/module/storage/store.js +387 -0
  210. package/lib/module/storage/store.js.map +1 -0
  211. package/lib/module/storage/types.js +16 -0
  212. package/lib/module/storage/types.js.map +1 -0
  213. package/lib/module/storage/validation.js +111 -0
  214. package/lib/module/storage/validation.js.map +1 -0
  215. package/lib/module/storage.js +4 -0
  216. package/lib/module/storage.js.map +1 -0
  217. package/lib/module/testing.js +4 -0
  218. package/lib/module/testing.js.map +1 -1
  219. package/lib/module/tilemap/chunkStats.js +27 -0
  220. package/lib/module/tilemap/chunkStats.js.map +1 -0
  221. package/lib/module/tilemap/definitions.js +308 -0
  222. package/lib/module/tilemap/definitions.js.map +1 -0
  223. package/lib/module/tilemap/errors.js +13 -0
  224. package/lib/module/tilemap/errors.js.map +1 -0
  225. package/lib/module/tilemap/index.js +10 -0
  226. package/lib/module/tilemap/index.js.map +1 -0
  227. package/lib/module/tilemap/movement.js +379 -0
  228. package/lib/module/tilemap/movement.js.map +1 -0
  229. package/lib/module/tilemap/queries.js +114 -0
  230. package/lib/module/tilemap/queries.js.map +1 -0
  231. package/lib/module/tilemap/tiledAdapter.js +141 -0
  232. package/lib/module/tilemap/tiledAdapter.js.map +1 -0
  233. package/lib/module/tilemap/types.js +4 -0
  234. package/lib/module/tilemap/types.js.map +1 -0
  235. package/lib/module/tilemap.js +4 -0
  236. package/lib/module/tilemap.js.map +1 -0
  237. package/lib/typescript/src/assets/defineAssets.d.ts +1 -1
  238. package/lib/typescript/src/assets/defineAssets.d.ts.map +1 -1
  239. package/lib/typescript/src/assets.d.ts +11 -0
  240. package/lib/typescript/src/assets.d.ts.map +1 -0
  241. package/lib/typescript/src/audio/createGameAudio.d.ts +5 -0
  242. package/lib/typescript/src/audio/createGameAudio.d.ts.map +1 -0
  243. package/lib/typescript/src/audio/errors.d.ts +6 -0
  244. package/lib/typescript/src/audio/errors.d.ts.map +1 -0
  245. package/lib/typescript/src/audio/index.d.ts +4 -0
  246. package/lib/typescript/src/audio/index.d.ts.map +1 -0
  247. package/lib/typescript/src/audio/resolver.d.ts +44 -0
  248. package/lib/typescript/src/audio/resolver.d.ts.map +1 -0
  249. package/lib/typescript/src/audio/types.d.ts +42 -0
  250. package/lib/typescript/src/audio/types.d.ts.map +1 -0
  251. package/lib/typescript/src/audio.d.ts +8 -0
  252. package/lib/typescript/src/audio.d.ts.map +1 -0
  253. package/lib/typescript/src/camera2d/bounds.d.ts +25 -0
  254. package/lib/typescript/src/camera2d/bounds.d.ts.map +1 -0
  255. package/lib/typescript/src/camera2d/extents.d.ts +17 -0
  256. package/lib/typescript/src/camera2d/extents.d.ts.map +1 -0
  257. package/lib/typescript/src/camera2d/follow.d.ts +24 -0
  258. package/lib/typescript/src/camera2d/follow.d.ts.map +1 -0
  259. package/lib/typescript/src/camera2d/index.d.ts +19 -0
  260. package/lib/typescript/src/camera2d/index.d.ts.map +1 -0
  261. package/lib/typescript/src/camera2d/interpolation.d.ts +17 -0
  262. package/lib/typescript/src/camera2d/interpolation.d.ts.map +1 -0
  263. package/lib/typescript/src/camera2d/shake.d.ts +20 -0
  264. package/lib/typescript/src/camera2d/shake.d.ts.map +1 -0
  265. package/lib/typescript/src/camera2d/transform.d.ts +44 -0
  266. package/lib/typescript/src/camera2d/transform.d.ts.map +1 -0
  267. package/lib/typescript/src/camera2d/types.d.ts +74 -0
  268. package/lib/typescript/src/camera2d/types.d.ts.map +1 -0
  269. package/lib/typescript/src/camera2d/validation.d.ts +30 -0
  270. package/lib/typescript/src/camera2d/validation.d.ts.map +1 -0
  271. package/lib/typescript/src/camera2d/visibility.d.ts +47 -0
  272. package/lib/typescript/src/camera2d/visibility.d.ts.map +1 -0
  273. package/lib/typescript/src/camera2d.d.ts +7 -0
  274. package/lib/typescript/src/camera2d.d.ts.map +1 -0
  275. package/lib/typescript/src/collision2d/colliders.d.ts +120 -0
  276. package/lib/typescript/src/collision2d/colliders.d.ts.map +1 -0
  277. package/lib/typescript/src/collision2d/debug.d.ts +67 -0
  278. package/lib/typescript/src/collision2d/debug.d.ts.map +1 -0
  279. package/lib/typescript/src/collision2d/filters.d.ts +28 -0
  280. package/lib/typescript/src/collision2d/filters.d.ts.map +1 -0
  281. package/lib/typescript/src/collision2d/index.d.ts +17 -0
  282. package/lib/typescript/src/collision2d/index.d.ts.map +1 -0
  283. package/lib/typescript/src/collision2d/intersections.d.ts +24 -0
  284. package/lib/typescript/src/collision2d/intersections.d.ts.map +1 -0
  285. package/lib/typescript/src/collision2d/manifolds.d.ts +39 -0
  286. package/lib/typescript/src/collision2d/manifolds.d.ts.map +1 -0
  287. package/lib/typescript/src/collision2d/segments.d.ts +24 -0
  288. package/lib/typescript/src/collision2d/segments.d.ts.map +1 -0
  289. package/lib/typescript/src/collision2d/spatialHash.d.ts +50 -0
  290. package/lib/typescript/src/collision2d/spatialHash.d.ts.map +1 -0
  291. package/lib/typescript/src/collision2d/sweeps.d.ts +60 -0
  292. package/lib/typescript/src/collision2d/sweeps.d.ts.map +1 -0
  293. package/lib/typescript/src/collision2d.d.ts +7 -0
  294. package/lib/typescript/src/collision2d.d.ts.map +1 -0
  295. package/lib/typescript/src/core/input/buttonPad.d.ts +59 -0
  296. package/lib/typescript/src/core/input/buttonPad.d.ts.map +1 -0
  297. package/lib/typescript/src/core/input/createInputBuffer.d.ts +1 -1
  298. package/lib/typescript/src/core/input/createInputBuffer.d.ts.map +1 -1
  299. package/lib/typescript/src/core/input/types.d.ts +7 -0
  300. package/lib/typescript/src/core/input/types.d.ts.map +1 -1
  301. package/lib/typescript/src/core/session/createGameSession.d.ts +4 -2
  302. package/lib/typescript/src/core/session/createGameSession.d.ts.map +1 -1
  303. package/lib/typescript/src/core/session/deepFreeze.d.ts +21 -1
  304. package/lib/typescript/src/core/session/deepFreeze.d.ts.map +1 -1
  305. package/lib/typescript/src/core/session/diagnostics.d.ts +2 -0
  306. package/lib/typescript/src/core/session/diagnostics.d.ts.map +1 -1
  307. package/lib/typescript/src/core/session/types.d.ts +69 -4
  308. package/lib/typescript/src/core/session/types.d.ts.map +1 -1
  309. package/lib/typescript/src/definition/defineGame.d.ts +12 -1
  310. package/lib/typescript/src/definition/defineGame.d.ts.map +1 -1
  311. package/lib/typescript/src/definition/types.d.ts +10 -1
  312. package/lib/typescript/src/definition/types.d.ts.map +1 -1
  313. package/lib/typescript/src/events/defineGameEvents.d.ts +26 -0
  314. package/lib/typescript/src/events/defineGameEvents.d.ts.map +1 -0
  315. package/lib/typescript/src/events/errors.d.ts +12 -0
  316. package/lib/typescript/src/events/errors.d.ts.map +1 -0
  317. package/lib/typescript/src/events/index.d.ts +6 -0
  318. package/lib/typescript/src/events/index.d.ts.map +1 -0
  319. package/lib/typescript/src/events/payload.d.ts +21 -0
  320. package/lib/typescript/src/events/payload.d.ts.map +1 -0
  321. package/lib/typescript/src/events/seed.d.ts +3 -0
  322. package/lib/typescript/src/events/seed.d.ts.map +1 -0
  323. package/lib/typescript/src/events/types.d.ts +42 -0
  324. package/lib/typescript/src/events/types.d.ts.map +1 -0
  325. package/lib/typescript/src/events.d.ts +12 -0
  326. package/lib/typescript/src/events.d.ts.map +1 -0
  327. package/lib/typescript/src/geometry/helpers.d.ts +35 -0
  328. package/lib/typescript/src/geometry/helpers.d.ts.map +1 -0
  329. package/lib/typescript/src/geometry/index.d.ts +4 -0
  330. package/lib/typescript/src/geometry/index.d.ts.map +1 -0
  331. package/lib/typescript/src/geometry/types.d.ts +49 -0
  332. package/lib/typescript/src/geometry/types.d.ts.map +1 -1
  333. package/lib/typescript/src/geometry/validation.d.ts +44 -0
  334. package/lib/typescript/src/geometry/validation.d.ts.map +1 -0
  335. package/lib/typescript/src/geometry.d.ts +7 -0
  336. package/lib/typescript/src/geometry.d.ts.map +1 -0
  337. package/lib/typescript/src/haptics/createGameHaptics.d.ts +3 -0
  338. package/lib/typescript/src/haptics/createGameHaptics.d.ts.map +1 -0
  339. package/lib/typescript/src/haptics/errors.d.ts +6 -0
  340. package/lib/typescript/src/haptics/errors.d.ts.map +1 -0
  341. package/lib/typescript/src/haptics/index.d.ts +4 -0
  342. package/lib/typescript/src/haptics/index.d.ts.map +1 -0
  343. package/lib/typescript/src/haptics/resolver.d.ts +22 -0
  344. package/lib/typescript/src/haptics/resolver.d.ts.map +1 -0
  345. package/lib/typescript/src/haptics/types.d.ts +37 -0
  346. package/lib/typescript/src/haptics/types.d.ts.map +1 -0
  347. package/lib/typescript/src/haptics.d.ts +8 -0
  348. package/lib/typescript/src/haptics.d.ts.map +1 -0
  349. package/lib/typescript/src/index.d.ts +10 -2
  350. package/lib/typescript/src/index.d.ts.map +1 -1
  351. package/lib/typescript/src/particles/createParticleSystem.d.ts +5 -0
  352. package/lib/typescript/src/particles/createParticleSystem.d.ts.map +1 -0
  353. package/lib/typescript/src/particles/defineParticleEffect.d.ts +3 -0
  354. package/lib/typescript/src/particles/defineParticleEffect.d.ts.map +1 -0
  355. package/lib/typescript/src/particles/errors.d.ts +5 -0
  356. package/lib/typescript/src/particles/errors.d.ts.map +1 -0
  357. package/lib/typescript/src/particles/index.d.ts +6 -0
  358. package/lib/typescript/src/particles/index.d.ts.map +1 -0
  359. package/lib/typescript/src/particles/sampling.d.ts +54 -0
  360. package/lib/typescript/src/particles/sampling.d.ts.map +1 -0
  361. package/lib/typescript/src/particles/types.d.ts +292 -0
  362. package/lib/typescript/src/particles/types.d.ts.map +1 -0
  363. package/lib/typescript/src/particles.d.ts +2 -0
  364. package/lib/typescript/src/particles.d.ts.map +1 -0
  365. package/lib/typescript/src/react/GameButtonPad.d.ts +84 -0
  366. package/lib/typescript/src/react/GameButtonPad.d.ts.map +1 -0
  367. package/lib/typescript/src/react/GamePointerInput.d.ts.map +1 -1
  368. package/lib/typescript/src/react/GameView.d.ts +27 -1
  369. package/lib/typescript/src/react/GameView.d.ts.map +1 -1
  370. package/lib/typescript/src/react/assets/createGameAssetStore.d.ts.map +1 -1
  371. package/lib/typescript/src/react/assets/useGameAssets.d.ts.map +1 -1
  372. package/lib/typescript/src/react/bindAppLifecycle.d.ts +7 -1
  373. package/lib/typescript/src/react/bindAppLifecycle.d.ts.map +1 -1
  374. package/lib/typescript/src/react/bindGameSession.d.ts.map +1 -1
  375. package/lib/typescript/src/react/camera2d/GameLayer2D.d.ts +24 -0
  376. package/lib/typescript/src/react/camera2d/GameLayer2D.d.ts.map +1 -0
  377. package/lib/typescript/src/react/camera2d/defineGameCamera2D.d.ts +44 -0
  378. package/lib/typescript/src/react/camera2d/defineGameCamera2D.d.ts.map +1 -0
  379. package/lib/typescript/src/react/camera2d/usePresentedCameraBinding.d.ts +22 -0
  380. package/lib/typescript/src/react/camera2d/usePresentedCameraBinding.d.ts.map +1 -0
  381. package/lib/typescript/src/react/cleanupList.d.ts +21 -0
  382. package/lib/typescript/src/react/cleanupList.d.ts.map +1 -0
  383. package/lib/typescript/src/react/instrumentation.d.ts +33 -3
  384. package/lib/typescript/src/react/instrumentation.d.ts.map +1 -1
  385. package/lib/typescript/src/react/lifecycleSource.d.ts +21 -0
  386. package/lib/typescript/src/react/lifecycleSource.d.ts.map +1 -0
  387. package/lib/typescript/src/react/particles/ParticleView.d.ts +65 -0
  388. package/lib/typescript/src/react/particles/ParticleView.d.ts.map +1 -0
  389. package/lib/typescript/src/react/particles/culling.d.ts +70 -0
  390. package/lib/typescript/src/react/particles/culling.d.ts.map +1 -0
  391. package/lib/typescript/src/react/particles/index.d.ts +7 -0
  392. package/lib/typescript/src/react/particles/index.d.ts.map +1 -0
  393. package/lib/typescript/src/react/particles/spriteXForm.d.ts +28 -0
  394. package/lib/typescript/src/react/particles/spriteXForm.d.ts.map +1 -0
  395. package/lib/typescript/src/react/particles/useParticlePresentation.d.ts +48 -0
  396. package/lib/typescript/src/react/particles/useParticlePresentation.d.ts.map +1 -0
  397. package/lib/typescript/src/react/pointerBinding.d.ts +38 -8
  398. package/lib/typescript/src/react/pointerBinding.d.ts.map +1 -1
  399. package/lib/typescript/src/react/pointerCamera.d.ts +20 -0
  400. package/lib/typescript/src/react/pointerCamera.d.ts.map +1 -0
  401. package/lib/typescript/src/react/pointerCoalescer.d.ts +17 -1
  402. package/lib/typescript/src/react/pointerCoalescer.d.ts.map +1 -1
  403. package/lib/typescript/src/react/sprites/GameSprite.d.ts +3 -10
  404. package/lib/typescript/src/react/sprites/GameSprite.d.ts.map +1 -1
  405. package/lib/typescript/src/react/sprites/GameWorld2D.d.ts +51 -6
  406. package/lib/typescript/src/react/sprites/GameWorld2D.d.ts.map +1 -1
  407. package/lib/typescript/src/react/sprites/Sprite.d.ts.map +1 -1
  408. package/lib/typescript/src/react/sprites/SpriteBatch.d.ts +22 -1
  409. package/lib/typescript/src/react/sprites/SpriteBatch.d.ts.map +1 -1
  410. package/lib/typescript/src/react/sprites/batchVisibility.d.ts +28 -0
  411. package/lib/typescript/src/react/sprites/batchVisibility.d.ts.map +1 -0
  412. package/lib/typescript/src/react/sprites/spriteSelection.d.ts +58 -0
  413. package/lib/typescript/src/react/sprites/spriteSelection.d.ts.map +1 -0
  414. package/lib/typescript/src/react/sprites/spriteTransform.d.ts +27 -12
  415. package/lib/typescript/src/react/sprites/spriteTransform.d.ts.map +1 -1
  416. package/lib/typescript/src/react/tilemap/TileMapLayer2D.d.ts +69 -0
  417. package/lib/typescript/src/react/tilemap/TileMapLayer2D.d.ts.map +1 -0
  418. package/lib/typescript/src/react/tilemap/tilePresentation.d.ts +217 -0
  419. package/lib/typescript/src/react/tilemap/tilePresentation.d.ts.map +1 -0
  420. package/lib/typescript/src/react/useGameSession.d.ts +48 -0
  421. package/lib/typescript/src/react/useGameSession.d.ts.map +1 -0
  422. package/lib/typescript/src/react/useGameSessionStatus.d.ts +23 -0
  423. package/lib/typescript/src/react/useGameSessionStatus.d.ts.map +1 -0
  424. package/lib/typescript/src/react/viewportBinding.d.ts +5 -1
  425. package/lib/typescript/src/react/viewportBinding.d.ts.map +1 -1
  426. package/lib/typescript/src/react.d.ts +18 -1
  427. package/lib/typescript/src/react.d.ts.map +1 -1
  428. package/lib/typescript/src/scene/defineScene.d.ts +22 -2
  429. package/lib/typescript/src/scene/defineScene.d.ts.map +1 -1
  430. package/lib/typescript/src/scene/types.d.ts +24 -4
  431. package/lib/typescript/src/scene/types.d.ts.map +1 -1
  432. package/lib/typescript/src/sprites/sampleSpriteClip.d.ts +26 -2
  433. package/lib/typescript/src/sprites/sampleSpriteClip.d.ts.map +1 -1
  434. package/lib/typescript/src/sprites/spriteAnimationState.d.ts +6 -7
  435. package/lib/typescript/src/sprites/spriteAnimationState.d.ts.map +1 -1
  436. package/lib/typescript/src/sprites.d.ts +10 -0
  437. package/lib/typescript/src/sprites.d.ts.map +1 -0
  438. package/lib/typescript/src/storage/adapters/asyncStorage.d.ts +18 -0
  439. package/lib/typescript/src/storage/adapters/asyncStorage.d.ts.map +1 -0
  440. package/lib/typescript/src/storage/adapters/memory.d.ts +16 -0
  441. package/lib/typescript/src/storage/adapters/memory.d.ts.map +1 -0
  442. package/lib/typescript/src/storage/errors.d.ts +37 -0
  443. package/lib/typescript/src/storage/errors.d.ts.map +1 -0
  444. package/lib/typescript/src/storage/index.d.ts +11 -0
  445. package/lib/typescript/src/storage/index.d.ts.map +1 -0
  446. package/lib/typescript/src/storage/schema.d.ts +22 -0
  447. package/lib/typescript/src/storage/schema.d.ts.map +1 -0
  448. package/lib/typescript/src/storage/serialization.d.ts +23 -0
  449. package/lib/typescript/src/storage/serialization.d.ts.map +1 -0
  450. package/lib/typescript/src/storage/store.d.ts +3 -0
  451. package/lib/typescript/src/storage/store.d.ts.map +1 -0
  452. package/lib/typescript/src/storage/types.d.ts +69 -0
  453. package/lib/typescript/src/storage/types.d.ts.map +1 -0
  454. package/lib/typescript/src/storage/validation.d.ts +24 -0
  455. package/lib/typescript/src/storage/validation.d.ts.map +1 -0
  456. package/lib/typescript/src/storage.d.ts +2 -0
  457. package/lib/typescript/src/storage.d.ts.map +1 -0
  458. package/lib/typescript/src/testing.d.ts +1 -0
  459. package/lib/typescript/src/testing.d.ts.map +1 -1
  460. package/lib/typescript/src/tilemap/chunkStats.d.ts +14 -0
  461. package/lib/typescript/src/tilemap/chunkStats.d.ts.map +1 -0
  462. package/lib/typescript/src/tilemap/definitions.d.ts +38 -0
  463. package/lib/typescript/src/tilemap/definitions.d.ts.map +1 -0
  464. package/lib/typescript/src/tilemap/errors.d.ts +7 -0
  465. package/lib/typescript/src/tilemap/errors.d.ts.map +1 -0
  466. package/lib/typescript/src/tilemap/index.d.ts +8 -0
  467. package/lib/typescript/src/tilemap/index.d.ts.map +1 -0
  468. package/lib/typescript/src/tilemap/movement.d.ts +52 -0
  469. package/lib/typescript/src/tilemap/movement.d.ts.map +1 -0
  470. package/lib/typescript/src/tilemap/queries.d.ts +21 -0
  471. package/lib/typescript/src/tilemap/queries.d.ts.map +1 -0
  472. package/lib/typescript/src/tilemap/tiledAdapter.d.ts +32 -0
  473. package/lib/typescript/src/tilemap/tiledAdapter.d.ts.map +1 -0
  474. package/lib/typescript/src/tilemap/types.d.ts +127 -0
  475. package/lib/typescript/src/tilemap/types.d.ts.map +1 -0
  476. package/lib/typescript/src/tilemap.d.ts +2 -0
  477. package/lib/typescript/src/tilemap.d.ts.map +1 -0
  478. package/package.json +100 -10
  479. package/src/assets/defineAssets.ts +31 -5
  480. package/src/assets.ts +27 -0
  481. package/src/audio/createGameAudio.ts +749 -0
  482. package/src/audio/errors.ts +12 -0
  483. package/src/audio/index.ts +9 -0
  484. package/src/audio/resolver.ts +74 -0
  485. package/src/audio/types.ts +47 -0
  486. package/src/audio.ts +13 -0
  487. package/src/camera2d/bounds.ts +69 -0
  488. package/src/camera2d/extents.ts +25 -0
  489. package/src/camera2d/follow.ts +165 -0
  490. package/src/camera2d/index.ts +29 -0
  491. package/src/camera2d/interpolation.ts +113 -0
  492. package/src/camera2d/shake.ts +90 -0
  493. package/src/camera2d/transform.ts +148 -0
  494. package/src/camera2d/types.ts +73 -0
  495. package/src/camera2d/validation.ts +126 -0
  496. package/src/camera2d/visibility.ts +181 -0
  497. package/src/camera2d.ts +6 -0
  498. package/src/collision2d/colliders.ts +292 -0
  499. package/src/collision2d/debug.ts +133 -0
  500. package/src/collision2d/filters.ts +48 -0
  501. package/src/collision2d/index.ts +74 -0
  502. package/src/collision2d/intersections.ts +82 -0
  503. package/src/collision2d/manifolds.ts +191 -0
  504. package/src/collision2d/segments.ts +176 -0
  505. package/src/collision2d/spatialHash.ts +211 -0
  506. package/src/collision2d/sweeps.ts +269 -0
  507. package/src/collision2d.ts +6 -0
  508. package/src/core/input/buttonPad.ts +235 -0
  509. package/src/core/input/createInputBuffer.ts +95 -14
  510. package/src/core/input/types.ts +7 -0
  511. package/src/core/session/createGameSession.ts +480 -53
  512. package/src/core/session/deepFreeze.ts +104 -3
  513. package/src/core/session/diagnostics.ts +2 -0
  514. package/src/core/session/types.ts +77 -4
  515. package/src/definition/defineGame.ts +61 -3
  516. package/src/definition/types.ts +10 -0
  517. package/src/events/defineGameEvents.ts +46 -0
  518. package/src/events/errors.ts +14 -0
  519. package/src/events/index.ts +14 -0
  520. package/src/events/payload.ts +234 -0
  521. package/src/events/seed.ts +33 -0
  522. package/src/events/types.ts +53 -0
  523. package/src/events.ts +20 -0
  524. package/src/geometry/helpers.ts +136 -0
  525. package/src/geometry/index.ts +14 -0
  526. package/src/geometry/types.ts +54 -0
  527. package/src/geometry/validation.ts +131 -0
  528. package/src/geometry.ts +6 -0
  529. package/src/haptics/createGameHaptics.ts +214 -0
  530. package/src/haptics/errors.ts +12 -0
  531. package/src/haptics/index.ts +3 -0
  532. package/src/haptics/resolver.ts +58 -0
  533. package/src/haptics/types.ts +48 -0
  534. package/src/haptics.ts +7 -0
  535. package/src/index.ts +37 -1
  536. package/src/particles/createParticleSystem.ts +505 -0
  537. package/src/particles/defineParticleEffect.ts +164 -0
  538. package/src/particles/errors.ts +6 -0
  539. package/src/particles/index.ts +5 -0
  540. package/src/particles/sampling.ts +141 -0
  541. package/src/particles/types.ts +327 -0
  542. package/src/particles.ts +1 -0
  543. package/src/react/GameButtonPad.tsx +436 -0
  544. package/src/react/GamePointerInput.tsx +73 -8
  545. package/src/react/GameView.tsx +160 -61
  546. package/src/react/assets/createGameAssetStore.ts +140 -107
  547. package/src/react/assets/useGameAssets.ts +63 -31
  548. package/src/react/bindAppLifecycle.ts +55 -19
  549. package/src/react/bindGameSession.ts +12 -2
  550. package/src/react/camera2d/GameLayer2D.tsx +43 -0
  551. package/src/react/camera2d/defineGameCamera2D.ts +59 -0
  552. package/src/react/camera2d/usePresentedCameraBinding.ts +185 -0
  553. package/src/react/cleanupList.ts +48 -0
  554. package/src/react/instrumentation.ts +31 -3
  555. package/src/react/lifecycleSource.ts +58 -0
  556. package/src/react/particles/ParticleView.tsx +358 -0
  557. package/src/react/particles/culling.ts +145 -0
  558. package/src/react/particles/index.ts +6 -0
  559. package/src/react/particles/spriteXForm.ts +72 -0
  560. package/src/react/particles/useParticlePresentation.ts +261 -0
  561. package/src/react/pointerBinding.ts +74 -16
  562. package/src/react/pointerCamera.ts +33 -0
  563. package/src/react/pointerCoalescer.ts +36 -10
  564. package/src/react/sprites/GameSprite.tsx +4 -33
  565. package/src/react/sprites/GameWorld2D.tsx +113 -7
  566. package/src/react/sprites/Sprite.tsx +51 -72
  567. package/src/react/sprites/SpriteBatch.tsx +74 -22
  568. package/src/react/sprites/batchVisibility.ts +76 -0
  569. package/src/react/sprites/spriteSelection.ts +133 -0
  570. package/src/react/sprites/spriteTransform.ts +46 -26
  571. package/src/react/tilemap/TileMapLayer2D.tsx +274 -0
  572. package/src/react/tilemap/tilePresentation.ts +491 -0
  573. package/src/react/useGameSession.ts +90 -0
  574. package/src/react/useGameSessionStatus.ts +53 -0
  575. package/src/react/viewportBinding.ts +5 -1
  576. package/src/react.ts +18 -1
  577. package/src/scene/defineScene.ts +47 -5
  578. package/src/scene/types.ts +37 -3
  579. package/src/sprites/sampleSpriteClip.ts +82 -14
  580. package/src/sprites/spriteAnimationState.ts +29 -25
  581. package/src/sprites.ts +22 -0
  582. package/src/storage/adapters/asyncStorage.ts +77 -0
  583. package/src/storage/adapters/memory.ts +58 -0
  584. package/src/storage/errors.ts +88 -0
  585. package/src/storage/index.ts +18 -0
  586. package/src/storage/schema.ts +147 -0
  587. package/src/storage/serialization.ts +248 -0
  588. package/src/storage/store.ts +380 -0
  589. package/src/storage/types.ts +76 -0
  590. package/src/storage/validation.ts +102 -0
  591. package/src/storage.ts +1 -0
  592. package/src/testing.ts +4 -0
  593. package/src/tilemap/chunkStats.ts +24 -0
  594. package/src/tilemap/definitions.ts +327 -0
  595. package/src/tilemap/errors.ts +11 -0
  596. package/src/tilemap/index.ts +10 -0
  597. package/src/tilemap/movement.ts +368 -0
  598. package/src/tilemap/queries.ts +136 -0
  599. package/src/tilemap/tiledAdapter.ts +165 -0
  600. package/src/tilemap/types.ts +119 -0
  601. package/src/tilemap.ts +1 -0
@@ -0,0 +1,261 @@
1
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
2
+ import { useSharedValue, type SharedValue } from 'react-native-reanimated';
3
+
4
+ import type {
5
+ GameLifecycleSource,
6
+ GameSessionStatus,
7
+ } from '../../core/session/types';
8
+ import type {
9
+ ParticleSystem,
10
+ ParticleUiRegistry,
11
+ } from '../../particles/types';
12
+
13
+ export type SessionStatus = GameSessionStatus;
14
+
15
+ /**
16
+ * What the presentation hook hands to views (T15-SF1): a SCALAR active-time
17
+ * clock written every running frame, plus the bounded emission registry
18
+ * transferred only when membership changes. No per-frame bulk arrays cross
19
+ * the runtime boundary.
20
+ */
21
+ export interface ParticlePresentation {
22
+ readonly clock: SharedValue<number>;
23
+ readonly registry: SharedValue<ParticleUiRegistry>;
24
+ /** Imperative manual-pause control, independent of the session source. */
25
+ setManualPaused(paused: boolean): void;
26
+ }
27
+
28
+ const EMPTY_REGISTRY: ParticleUiRegistry = Object.freeze({
29
+ registryRevision: -1,
30
+ activeClock: 0,
31
+ effects: Object.freeze({}),
32
+ });
33
+
34
+ function defaultSchedule(tick: () => void): () => void {
35
+ const id = requestAnimationFrame(tick);
36
+ return () => cancelAnimationFrame(id);
37
+ }
38
+
39
+ /**
40
+ * Own THE exclusive presentation clock for one system (T15-F1/T15-RF3).
41
+ *
42
+ * Per-frame runtime work is ONE scalar write (`clock.value`); the bounded
43
+ * emission registry is transferred only when membership changes (T15-SF1).
44
+ *
45
+ * Pause sources are applied through ONE effect-owned control so transitions
46
+ * stop/start the scheduler immediately — including while the driver is idle
47
+ * or asleep (T15-SF3). Scheduling runs only when the system is running AND
48
+ * at least one particle is active; it fully stops otherwise and restarts
49
+ * from resume/wake transitions.
50
+ */
51
+ export function useParticlePresentation(
52
+ system: ParticleSystem,
53
+ options?: {
54
+ /**
55
+ * The owning session's lifecycle source (T20.3) — the preferred way to
56
+ * follow a session. Supplied by `GameView` through
57
+ * `useGameLifecycleSource()`. When set, it takes precedence over the
58
+ * legacy `sessionStatus`/`sessionSubscribe` options.
59
+ */
60
+ readonly lifecycle?: GameLifecycleSource;
61
+ /** Legacy reader: read the owning session's status each frame / on change. */
62
+ readonly sessionStatus?: () => SessionStatus;
63
+ /** Legacy reactive subscription for session status changes. */
64
+ readonly sessionSubscribe?: (
65
+ listener: (status: SessionStatus) => void,
66
+ ) => () => void;
67
+ /** Independent user/lab pause reader; a running session cannot cancel it. */
68
+ readonly manualPaused?: () => boolean;
69
+ /** Injectable scheduler for deterministic headless/mounted tests. */
70
+ readonly schedule?: (tick: () => void) => () => void;
71
+ /** Injectable clock for deterministic deltas in tests. */
72
+ readonly now?: () => number;
73
+ },
74
+ ): ParticlePresentation {
75
+ const binding = useMemo(() => system.bindPresentation(), [system]);
76
+ const clock = useSharedValue(binding.activeClock);
77
+ const registry = useSharedValue<ParticleUiRegistry>(EMPTY_REGISTRY);
78
+ // T20F-R2: the driver effect must key ONLY on ownership inputs. Shared
79
+ // values are stable in Reanimated; the refs keep the effect closures
80
+ // pointing at the latest instance even where mocks hand back fresh objects.
81
+ const clockRef = useRef(clock);
82
+ const registryRef = useRef(registry);
83
+ useEffect(() => {
84
+ clockRef.current = clock;
85
+ registryRef.current = registry;
86
+ }, [clock, registry]);
87
+
88
+ // Latest-source refs (frame loop + reactive callbacks read these).
89
+ const lifecycleRef = useRef(options?.lifecycle);
90
+ lifecycleRef.current = options?.lifecycle;
91
+ const sessionRef = useRef(options?.sessionStatus);
92
+ sessionRef.current = options?.sessionStatus;
93
+ const manualReaderRef = useRef(options?.manualPaused);
94
+ manualReaderRef.current = options?.manualPaused;
95
+ const scheduleRef = useRef(options?.schedule ?? defaultSchedule);
96
+ const nowRef = useRef(options?.now ?? (() => Date.now()));
97
+ // Manual pause lives OUTSIDE render so the imperative setter is stable and
98
+ // reactive without depending on animation frames.
99
+ const manualPausedRef = useRef(false);
100
+
101
+ // Stable control ref owned by the effect (T15-TF2): the public setter and
102
+ // every pause transition route through this without capturing stale state.
103
+ const controlRef = useRef<{
104
+ applyPause(): void;
105
+ syncRegistry(): void;
106
+ updateScheduling(): void;
107
+ }>({ applyPause: () => {}, syncRegistry: () => {}, updateScheduling: () => {} });
108
+
109
+ // T20F-R2: STABLE across re-renders — it reads only refs plus `system`, so
110
+ // the driver effect below keeps a single acquire/subscription for the
111
+ // lifetime of one system instead of rebinding on every parent render.
112
+ const applyCombinedPause = useCallback((): void => {
113
+ if (system.status === 'disposed') return;
114
+ const session = lifecycleRef.current
115
+ ? lifecycleRef.current.getStatus()
116
+ : (sessionRef.current?.() ?? 'running');
117
+ const effectivePaused =
118
+ manualPausedRef.current ||
119
+ (manualReaderRef.current?.() ?? false) ||
120
+ session === 'paused' ||
121
+ session === 'disposed';
122
+ if (effectivePaused) system.pauseIfRunning();
123
+ else system.resumeIfPaused();
124
+ }, [system]);
125
+
126
+ useEffect(() => {
127
+ const driver = binding.acquireDriver();
128
+ let cancelled = false;
129
+ let cancelSchedule: (() => void) | null = null;
130
+ let last = nowRef.current();
131
+
132
+ const stopScheduling = (): void => {
133
+ if (cancelSchedule) {
134
+ cancelSchedule();
135
+ cancelSchedule = null;
136
+ }
137
+ };
138
+
139
+ const startScheduling = (): void => {
140
+ if (cancelled || cancelSchedule !== null) return;
141
+ last = nowRef.current();
142
+ let canceller: (() => void) | null = null;
143
+ // The executed tick clears its own handle so the next frame may be
144
+ // scheduled from inside stepFrame (self-perpetuating loop).
145
+ canceller = scheduleRef.current(() => {
146
+ if (cancelSchedule === canceller) cancelSchedule = null;
147
+ stepFrame();
148
+ });
149
+ cancelSchedule = canceller ?? null;
150
+ };
151
+
152
+ const syncRegistry = (): void => {
153
+ if (binding.registryRevision !== registryRef.current.value.registryRevision) {
154
+ // Bounded transfer: only on membership changes (T15-SF1). Expiration
155
+ // bumps the revision too, so the terminal prune ships (T15-TF1).
156
+ registryRef.current.value = binding.buildUiRegistry();
157
+ }
158
+ };
159
+
160
+ const stepFrame = (): void => {
161
+ if (cancelled) return;
162
+ const now = nowRef.current();
163
+ const dt = Math.max(0, Math.min((now - last) / 1000, 0.1));
164
+ last = now;
165
+
166
+ applyCombinedPause();
167
+ driver.step(dt);
168
+ syncRegistry();
169
+
170
+ // ALWAYS publish the terminal scalar — including the step that
171
+ // transitions to zero actives, so renderers hide the expired record
172
+ // before we sleep (T15-TF1).
173
+ clockRef.current.value = binding.activeClock;
174
+
175
+ // T20L-R2: the frame path enforces the same running guard as the
176
+ // reactive path — a paused step cannot expire particles, so scheduling
177
+ // another frame while paused would spin the driver forever.
178
+ if (system.status === 'running' && !driver.isIdle()) {
179
+ startScheduling();
180
+ return;
181
+ }
182
+ // Paused or idle: fully stop; resume transitions and emissions restart us.
183
+ stopScheduling();
184
+ };
185
+
186
+ // Effect-owned scheduling control (T15-TF2): pause transitions call this
187
+ // synchronously via the stable ref.
188
+ controlRef.current = {
189
+ applyPause: applyCombinedPause,
190
+ syncRegistry,
191
+ updateScheduling(): void {
192
+ applyCombinedPause();
193
+ syncRegistry();
194
+ if (cancelled || system.status === 'disposed') {
195
+ stopScheduling();
196
+ return;
197
+ }
198
+ // Schedule only when running AND something is active.
199
+ if (system.status === 'running' && !driver.isIdle()) {
200
+ startScheduling();
201
+ } else {
202
+ stopScheduling();
203
+ }
204
+ },
205
+ };
206
+
207
+ // Reactive pause application + registry sync + reschedule.
208
+ driver.setWakeListener(() => controlRef.current.updateScheduling());
209
+
210
+ // Initial synchronous application at bind time.
211
+ applyCombinedPause();
212
+
213
+ stepFrame();
214
+
215
+ return () => {
216
+ cancelled = true;
217
+ driver.setWakeListener(null);
218
+ stopScheduling();
219
+ driver.release();
220
+ };
221
+ }, [system, binding, applyCombinedPause]);
222
+
223
+ // T20F-R2: the lifecycle subscription is keyed by the SOURCE identity, not
224
+ // by render — one subscribe/detach per system generation. Status changes
225
+ // route through the effect-owned control so pause transitions stay
226
+ // synchronous without rebinding the driver.
227
+ const lifecycleSource = options?.lifecycle ?? null;
228
+ const legacySubscribe = options?.sessionSubscribe ?? null;
229
+ useEffect(() => {
230
+ const onSessionStatus = (status: SessionStatus): void => {
231
+ sessionRef.current = () => status;
232
+ controlRef.current.updateScheduling();
233
+ };
234
+ const detach =
235
+ lifecycleSource !== null
236
+ ? lifecycleSource.subscribe(onSessionStatus)
237
+ : legacySubscribe?.(onSessionStatus);
238
+ // T20F-R2 re-review: a REPLACED source may already be paused (or running)
239
+ // — apply its current status immediately instead of waiting for its next
240
+ // transition, so paused emissions are never accepted in between.
241
+ controlRef.current.updateScheduling();
242
+ return detach;
243
+ }, [lifecycleSource, legacySubscribe]);
244
+
245
+ // Initial registry transfer at bind time.
246
+ useEffect(() => {
247
+ registryRef.current.value = binding.buildUiRegistry();
248
+ }, [binding]);
249
+
250
+ const setManualPaused = useCallback(
251
+ (paused: boolean): void => {
252
+ manualPausedRef.current = paused;
253
+ // Route through the effect-owned control: applies combined sources AND
254
+ // stops/starts the scheduler immediately (T15-TF2).
255
+ controlRef.current.updateScheduling();
256
+ },
257
+ [],
258
+ );
259
+
260
+ return { clock, registry, setManualPaused };
261
+ }
@@ -1,6 +1,16 @@
1
+ import type { CameraCut2D } from '../camera2d';
2
+ import { logicalToWorld2D } from '../camera2d';
1
3
  import type { InputController } from '../core/input/types';
2
4
  import type { Point2D } from '../geometry/types';
3
5
  import { containsSurfacePoint, surfaceToWorld, type ResolvedViewport2D } from '../viewport2d';
6
+ /** One accepted surface -> world conversion with its exact inputs (T12-TF3). */
7
+ export interface PointerSample2D {
8
+ readonly surface: { readonly x: number; readonly y: number };
9
+ readonly viewport: ResolvedViewport2D;
10
+ readonly camera: CameraCut2D | undefined;
11
+ readonly world: { readonly x: number; readonly y: number };
12
+ }
13
+
4
14
  import type { CoalescedPointerEvent } from './pointerCoalescer';
5
15
 
6
16
  /**
@@ -9,6 +19,12 @@ import type { CoalescedPointerEvent } from './pointerCoalescer';
9
19
  * replacement carry the old epoch and are rejected on the RN runtime, so a
10
20
  * stale begin cannot reacquire input with old coordinates and a stale
11
21
  * terminal edge cannot release a newer capture that reused the pointer id.
22
+ *
23
+ * T12-F4: the packet also carries the presented camera cut sampled AT
24
+ * EVENT TIME on the UI runtime. JS inverts through that stamp — never a
25
+ * later lazy read — so the world coordinate matches the camera under the
26
+ * finger when the touch happened, even while the camera follows, zooms,
27
+ * rotates, or shakes.
12
28
  */
13
29
  export type PointerPacket = CoalescedPointerEvent & {
14
30
  /** Monotonic adapter-owned binding generation (F3 follow-up). */
@@ -19,6 +35,8 @@ export type PointerPacket = CoalescedPointerEvent & {
19
35
  readonly seq: number;
20
36
  /** UI-runtime timestamp of the forward (F1 latency causality). */
21
37
  readonly atMs: number;
38
+ /** The presented camera cut at event time; absent for no-camera games. */
39
+ readonly camera?: CameraCut2D | undefined;
22
40
  };
23
41
 
24
42
  /** Monotonic generation source for factory-created bindings (F3). */
@@ -32,6 +50,12 @@ export interface PointerBindingIdentity<TName extends string> {
32
50
  readonly action: TName;
33
51
  /** Identity token for the viewport provider (changes on layout owner swaps). */
34
52
  readonly viewport: unknown;
53
+ /**
54
+ * Identity token for the presented camera provider (T12.4). Changes when
55
+ * the camera surface is replaced, so a fresh binding generation stamps
56
+ * packets under the new camera owner.
57
+ */
58
+ readonly camera: unknown;
35
59
  }
36
60
 
37
61
  /** A binding plus the identity it was created for. */
@@ -53,7 +77,8 @@ export function createPointerBinding<TName extends string>(
53
77
  previous !== undefined &&
54
78
  previous.identity.input === identity.input &&
55
79
  previous.identity.action === identity.action &&
56
- previous.identity.viewport === identity.viewport
80
+ previous.identity.viewport === identity.viewport &&
81
+ previous.identity.camera === identity.camera
57
82
  ) {
58
83
  return { entry: previous, created: false };
59
84
  }
@@ -78,9 +103,11 @@ export function createPointerBinding<TName extends string>(
78
103
  * Platform-neutral pointer binding seam.
79
104
  *
80
105
  * It converts gesture positions from surface coordinates into logical world
81
- * coordinates through the current resolved viewport, rejects begins that
106
+ * coordinates through the current resolved viewport (T12.4: and through the
107
+ * currently presented camera when the game has one), rejects begins that
82
108
  * start in `fit` letterbox space, and forwards semantic events into the
83
- * session input buffer. The high-level `handleTouches*` methods mirror the
109
+ * session input buffer. Containment always happens BEFORE camera inversion:
110
+ * letterbox space is rejected regardless of the camera. The high-level `handleTouches*` methods mirror the
84
111
  * adapter's touch dispatch (including forwarding the final up position) so
85
112
  * the full adapter behavior is testable without mounting native gesture
86
113
  * views. Ownership and neutralization live in the input buffer.
@@ -89,6 +116,7 @@ export class PointerBinding<TActionName extends string> {
89
116
  readonly #action: TActionName;
90
117
  readonly #input: InputController<TActionName>;
91
118
  readonly #getViewport: () => ResolvedViewport2D | undefined;
119
+ readonly #onSample: ((sample: PointerSample2D) => void) | undefined;
92
120
  readonly #generation: number;
93
121
  #disposed = false;
94
122
 
@@ -97,13 +125,39 @@ export class PointerBinding<TActionName extends string> {
97
125
  input: InputController<TActionName>,
98
126
  getViewport: () => ResolvedViewport2D | undefined,
99
127
  generation: number,
128
+ onSample?: (sample: PointerSample2D) => void,
100
129
  ) {
101
130
  this.#action = action;
102
131
  this.#input = input;
103
132
  this.#getViewport = getViewport;
133
+ this.#onSample = onSample;
104
134
  this.#generation = generation;
105
135
  }
106
136
 
137
+ /**
138
+ * Surface -> world through the viewport and the EVENT-TIME camera cut
139
+ * (T12.4, T12-F4).
140
+ *
141
+ * The frozen order: inverse viewport first, then inverse camera, using
142
+ * the camera stamp sampled by the UI worklet when the touch happened —
143
+ * the same camera the renderer drew at that moment. Without a camera
144
+ * stamp this is exactly `surfaceToWorld`.
145
+ */
146
+ #toWorld(viewport: ResolvedViewport2D, point: Point2D, camera: CameraCut2D | undefined): Point2D {
147
+ const logical = surfaceToWorld(viewport, point);
148
+ const world =
149
+ camera === undefined ? logical : logicalToWorld2D(logical, camera.camera, viewport.visibleLogicalBounds);
150
+ // T12-TF3: report one accepted conversion with its exact inputs and
151
+ // output — the lab measures the round trip from the real pipeline.
152
+ this.#onSample?.({
153
+ surface: { x: point.x, y: point.y },
154
+ viewport,
155
+ camera,
156
+ world,
157
+ });
158
+ return world;
159
+ }
160
+
107
161
  /**
108
162
  * The monotonic adapter-owned generation this binding belongs to (F3).
109
163
  * Generations never reset to zero, so a replacement binding and the
@@ -129,13 +183,13 @@ export class PointerBinding<TActionName extends string> {
129
183
  }
130
184
  switch (packet.kind) {
131
185
  case 'begin':
132
- this.handleTouchesDown(packet.pointerId, packet.x, packet.y);
186
+ this.handleTouchesDown(packet.pointerId, packet.x, packet.y, packet.camera);
133
187
  break;
134
188
  case 'move':
135
- this.handleTouchesMove(packet.pointerId, packet.x, packet.y);
189
+ this.handleTouchesMove(packet.pointerId, packet.x, packet.y, packet.camera);
136
190
  break;
137
191
  case 'end':
138
- this.handleTouchesUp(packet.pointerId, packet.x, packet.y);
192
+ this.handleTouchesUp(packet.pointerId, packet.x, packet.y, packet.camera);
139
193
  break;
140
194
  case 'cancel':
141
195
  this.handleTouchesCancelled();
@@ -150,7 +204,11 @@ export class PointerBinding<TActionName extends string> {
150
204
  * Returns `false` when the layout is invalid or the point starts in
151
205
  * letterbox space; the gesture must be rejected and never becomes the owner.
152
206
  */
153
- begin(pointerId: number, surfacePoint: Point2D): boolean {
207
+ begin(
208
+ pointerId: number,
209
+ surfacePoint: Point2D,
210
+ camera?: CameraCut2D,
211
+ ): boolean {
154
212
  if (this.#disposed) {
155
213
  return false;
156
214
  }
@@ -161,12 +219,12 @@ export class PointerBinding<TActionName extends string> {
161
219
  if (!containsSurfacePoint(viewport, surfacePoint)) {
162
220
  return false;
163
221
  }
164
- this.#input.begin(this.#action, pointerId, surfaceToWorld(viewport, surfacePoint));
222
+ this.#input.begin(this.#action, pointerId, this.#toWorld(viewport, surfacePoint, camera));
165
223
  return true;
166
224
  }
167
225
 
168
226
  /** Move a pointer. Conversion remains unbounded outside content bounds. */
169
- move(pointerId: number, surfacePoint: Point2D): void {
227
+ move(pointerId: number, surfacePoint: Point2D, camera?: CameraCut2D): void {
170
228
  if (this.#disposed) {
171
229
  return;
172
230
  }
@@ -174,7 +232,7 @@ export class PointerBinding<TActionName extends string> {
174
232
  if (viewport === undefined) {
175
233
  return;
176
234
  }
177
- this.#input.move(this.#action, pointerId, surfaceToWorld(viewport, surfacePoint));
235
+ this.#input.move(this.#action, pointerId, this.#toWorld(viewport, surfacePoint, camera));
178
236
  }
179
237
 
180
238
  /** End a pointer. The owning pointer is released by the input buffer. */
@@ -194,13 +252,13 @@ export class PointerBinding<TActionName extends string> {
194
252
  }
195
253
 
196
254
  /** Handle a touch-down gesture event with a surface position. */
197
- handleTouchesDown(pointerId: number, x: number, y: number): boolean {
198
- return this.begin(pointerId, { x, y });
255
+ handleTouchesDown(pointerId: number, x: number, y: number, camera?: CameraCut2D): boolean {
256
+ return this.begin(pointerId, { x, y }, camera);
199
257
  }
200
258
 
201
259
  /** Handle a touch-move gesture event with a surface position. */
202
- handleTouchesMove(pointerId: number, x: number, y: number): void {
203
- this.move(pointerId, { x, y });
260
+ handleTouchesMove(pointerId: number, x: number, y: number, camera?: CameraCut2D): void {
261
+ this.move(pointerId, { x, y }, camera);
204
262
  }
205
263
 
206
264
  /**
@@ -209,8 +267,8 @@ export class PointerBinding<TActionName extends string> {
209
267
  * The final position is forwarded before ownership ends so the documented
210
268
  * release frame contains the actual point where the pointer lifted.
211
269
  */
212
- handleTouchesUp(pointerId: number, x: number, y: number): void {
213
- this.move(pointerId, { x, y });
270
+ handleTouchesUp(pointerId: number, x: number, y: number, camera?: CameraCut2D): void {
271
+ this.move(pointerId, { x, y }, camera);
214
272
  this.end(pointerId);
215
273
  }
216
274
 
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Event-time camera selection for pointer packets (T12-SF1, T12-TF1).
3
+ *
4
+ * Internal module (not part of the public barrel): the ONE rule that pairs
5
+ * a forwarded pointer event with the presented camera at the event's own
6
+ * native sample. `GamePointerInput` and the focused tests import the same
7
+ * function, so the test can never drift from production.
8
+ */
9
+ import type { CameraCut2D } from '../camera2d';
10
+ import type { CoalescedPointerEvent } from './pointerCoalescer';
11
+
12
+ /** A move's explicit capture: `captured: true` even when the value is
13
+ * undefined, so a captured-undefined camera is distinguishable from "no
14
+ * stamp" and never falls back to a later presentation (T12-SF1). */
15
+ export interface PointerCameraCapture2D {
16
+ readonly captured: true;
17
+ readonly value: CameraCut2D | undefined;
18
+ }
19
+
20
+ /** The event-time camera for one forwarded event (worklet-safe). */
21
+ export function packetCameraFor(
22
+ forwarded: CoalescedPointerEvent,
23
+ presented: CameraCut2D | undefined,
24
+ ): CameraCut2D | undefined {
25
+ 'worklet';
26
+ if (forwarded.kind === 'move') {
27
+ const stamp = forwarded.stamp as PointerCameraCapture2D | undefined;
28
+ // A move ALWAYS carries its capture (possibly undefined): a captured
29
+ // undefined stays undefined — never fall back to a later camera.
30
+ return stamp !== undefined ? stamp.value : presented;
31
+ }
32
+ return presented;
33
+ }
@@ -24,7 +24,19 @@
24
24
 
25
25
  export type CoalescedPointerEvent =
26
26
  | { readonly kind: 'begin'; readonly pointerId: number; readonly x: number; readonly y: number }
27
- | { readonly kind: 'move'; readonly pointerId: number; readonly x: number; readonly y: number }
27
+ | {
28
+ readonly kind: 'move';
29
+ readonly pointerId: number;
30
+ readonly x: number;
31
+ readonly y: number;
32
+ /**
33
+ * Opaque event-time stamp (T12-RF3): captured with the native sample
34
+ * that produced this move and carried through deferral, so the
35
+ * presenter pairs coordinates and presentation state from the SAME
36
+ * native sample, never from a later flush frame.
37
+ */
38
+ readonly stamp?: unknown;
39
+ }
28
40
  | { readonly kind: 'end'; readonly pointerId: number; readonly x: number; readonly y: number }
29
41
  | { readonly kind: 'cancel' };
30
42
 
@@ -47,7 +59,7 @@ interface ActivePointer {
47
59
  readonly pointerId: number;
48
60
  readonly lastForwardMs: number;
49
61
  readonly pendingMove:
50
- | { readonly x: number; readonly y: number }
62
+ | { readonly x: number; readonly y: number; readonly stamp?: unknown }
51
63
  | undefined;
52
64
  }
53
65
 
@@ -60,11 +72,20 @@ export interface PointerCoalescerState {
60
72
  /** One native touch input consumed by the pure coalescer reducer. */
61
73
  export type PointerCoalescerInput =
62
74
  | {
63
- readonly kind: 'down' | 'move' | 'up';
75
+ readonly kind: 'down' | 'up';
76
+ readonly pointerId: number;
77
+ readonly x: number;
78
+ readonly y: number;
79
+ readonly nowMs: number;
80
+ }
81
+ | {
82
+ readonly kind: 'move';
64
83
  readonly pointerId: number;
65
84
  readonly x: number;
66
85
  readonly y: number;
67
86
  readonly nowMs: number;
87
+ /** Event-time stamp paired with this native sample (T12-RF3). */
88
+ readonly stamp?: unknown;
68
89
  }
69
90
  | { readonly kind: 'cancel'; readonly nowMs: number }
70
91
  | { readonly kind: 'flush'; readonly nowMs: number }
@@ -158,6 +179,7 @@ export function reducePointerCoalescer(
158
179
  pointerId: active.pointerId,
159
180
  x: active.pendingMove.x,
160
181
  y: active.pendingMove.y,
182
+ stamp: active.pendingMove.stamp,
161
183
  },
162
184
  ],
163
185
  };
@@ -182,12 +204,15 @@ export function reducePointerCoalescer(
182
204
  };
183
205
  }
184
206
 
207
+ // The remaining branch is the move input (down/up/cancel/flush/reset
208
+ // returned above); its optional stamp rides with the sample.
209
+ const moveInput = input as Extract<PointerCoalescerInput, { kind: 'move' }>;
185
210
  const shouldForward =
186
- input.nowMs - active.lastForwardMs >= state.maxMoveIntervalMs;
211
+ moveInput.nowMs - active.lastForwardMs >= state.maxMoveIntervalMs;
187
212
  const nextActive: ActivePointer = {
188
- pointerId: input.pointerId,
189
- lastForwardMs: shouldForward ? input.nowMs : active.lastForwardMs,
190
- pendingMove: shouldForward ? undefined : { x: input.x, y: input.y },
213
+ pointerId: moveInput.pointerId,
214
+ lastForwardMs: shouldForward ? moveInput.nowMs : active.lastForwardMs,
215
+ pendingMove: shouldForward ? undefined : { x: moveInput.x, y: moveInput.y, stamp: moveInput.stamp },
191
216
  };
192
217
  return {
193
218
  state: { ...state, active: nextActive },
@@ -195,9 +220,10 @@ export function reducePointerCoalescer(
195
220
  ? [
196
221
  {
197
222
  kind: 'move',
198
- pointerId: input.pointerId,
199
- x: input.x,
200
- y: input.y,
223
+ pointerId: moveInput.pointerId,
224
+ x: moveInput.x,
225
+ y: moveInput.y,
226
+ stamp: moveInput.stamp,
201
227
  },
202
228
  ]
203
229
  : [],
@@ -13,8 +13,12 @@ import type { CommitFrame } from '../../core/session/types';
13
13
  import type { SceneSnapshot } from '../../scene/types';
14
14
  import type { SceneMap } from '../../definition/types';
15
15
  import type { LoadedImage, LoadedSpriteSheet } from '../../assets/types';
16
+ import { spriteFrameNameForClip } from '../../sprites/sampleSpriteClip';
16
17
  import { Sprite, type SpriteAnimatable, type SpriteAnimatableBoolean, type SpriteProps } from './Sprite';
17
18
 
19
+ /** Re-exported from the single sampler contract (GS-ANIMATION-01). */
20
+ export { spriteFrameNameForClip };
21
+
18
22
  /** Interpolation context for the select mapper. */
19
23
  export interface GameSpriteSelectContext<
20
24
  TScenes extends SceneMap,
@@ -70,39 +74,6 @@ export interface GameSpriteProps<
70
74
  readonly select: (context: GameSpriteSelectContext<TScenes, TSceneName>) => GameSpriteSelection;
71
75
  }
72
76
 
73
- /**
74
- * Select the frame name for a clip + elapsed time (loop/once semantics).
75
- * Reads the descriptor's animation table; the result is resolved against
76
- * the frame rectangles by the caller. Reuses the pure sampler's semantics.
77
- */
78
- export function spriteFrameNameForClip(
79
- animations: Readonly<
80
- Record<
81
- string,
82
- {
83
- readonly frames: readonly string[];
84
- readonly frameDurationMs: number;
85
- readonly mode: 'loop' | 'once';
86
- }
87
- >
88
- >,
89
- clip: string,
90
- elapsedMs: number,
91
- ): string {
92
- 'worklet';
93
- const animation = animations[clip];
94
- if (animation === undefined || animation.frames.length === 0) {
95
- return clip;
96
- }
97
- const duration = animation.frameDurationMs;
98
- const count = animation.frames.length;
99
- const index =
100
- animation.mode === 'once'
101
- ? Math.min(Math.floor(elapsedMs / duration), count - 1)
102
- : Math.floor(elapsedMs / duration) % count;
103
- return animation.frames[index] ?? animation.frames[0] ?? clip;
104
- }
105
-
106
77
  export function GameSprite<
107
78
  TScenes extends SceneMap,
108
79
  TSceneName extends Extract<keyof TScenes, string>,