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
@@ -1,14 +1,18 @@
1
1
  /**
2
- * `GameWorld2D` — the viewport transform group (T7.6).
2
+ * `GameWorld2D` — the viewport + camera transform group (T7.6, T12.5).
3
3
  *
4
- * Applies the resolved viewport offset/scale exactly once to all child
5
- * sprites. It adds no camera state, subscribes no React per frame, and is
6
- * not a camera API. Raw Skia nodes may be nested inside.
4
+ * Applies the resolved viewport offset/scale to all child sprites, and —
5
+ * when the game opts into a camera — composes the presented camera
6
+ * transform BEFORE the viewport. The group's element list maps world ->
7
+ * surface directly; `GameLayer2D` children consume the same camera through
8
+ * the world context and apply only their parallax correction, so layers
9
+ * never double-apply the camera.
7
10
  */
8
- import type { ReactNode } from 'react';
11
+ import { createContext, useContext, type ReactNode } from 'react';
9
12
  import { Group } from '@shopify/react-native-skia';
10
13
  import { useDerivedValue, type SharedValue } from 'react-native-reanimated';
11
14
 
15
+ import type { CameraCut2D } from '../../camera2d';
12
16
  import type { ResolvedViewport2D } from '../../viewport2d/types';
13
17
 
14
18
  /**
@@ -33,14 +37,116 @@ export function viewportTransform(viewport: ResolvedViewport2D | undefined): rea
33
37
  ];
34
38
  }
35
39
 
40
+ /**
41
+ * The composed camera + viewport transform (T12.5).
42
+ *
43
+ * Skia applies the element list last-first, so the list below is the
44
+ * forward mapping `surface = viewport(L + rotate(P - C, -R) * Z)`:
45
+ * translate(-C) -> scale(Z) -> rotate(-R) -> translate(L) -> viewport.
46
+ */
47
+ export function cameraViewportTransform2D(
48
+ camera: CameraCut2D | undefined,
49
+ viewport: ResolvedViewport2D | undefined,
50
+ ): readonly (
51
+ | { readonly translateX: number }
52
+ | { readonly translateY: number }
53
+ | { readonly scaleX: number }
54
+ | { readonly scaleY: number }
55
+ | { readonly rotate: number }
56
+ )[] {
57
+ 'worklet';
58
+ if (camera === undefined || viewport === undefined) {
59
+ return [];
60
+ }
61
+ const { center, zoom, rotationRadians } = camera.camera;
62
+ const view = viewport.visibleLogicalBounds;
63
+ const logicalX = view.x + view.width / 2;
64
+ const logicalY = view.y + view.height / 2;
65
+ return [
66
+ { translateX: viewport.offsetX },
67
+ { translateY: viewport.offsetY },
68
+ { scaleX: viewport.scale },
69
+ { scaleY: viewport.scale },
70
+ { translateX: logicalX },
71
+ { translateY: logicalY },
72
+ { rotate: -rotationRadians },
73
+ { scaleX: zoom },
74
+ { scaleY: zoom },
75
+ { translateX: -center.x },
76
+ { translateY: -center.y },
77
+ ];
78
+ }
79
+
80
+ /**
81
+ * The parallax correction for one layer (T12.5).
82
+ *
83
+ * A layer with factor p draws with the camera whose effective center is
84
+ * `C' = L + (C - L) * p` per axis. Since zoom and rotation apply fully at
85
+ * every factor, the correction relative to the parent camera is exactly a
86
+ * translation by `(C - L) * (1 - p)` in world units.
87
+ */
88
+ export function layerParallaxTransform2D(
89
+ camera: CameraCut2D | undefined,
90
+ viewport: ResolvedViewport2D | undefined,
91
+ parallaxX: number,
92
+ parallaxY: number,
93
+ ): readonly ({ readonly translateX: number } | { readonly translateY: number })[] {
94
+ 'worklet';
95
+ if (camera === undefined || viewport === undefined) {
96
+ return [];
97
+ }
98
+ const view = viewport.visibleLogicalBounds;
99
+ const logicalX = view.x + view.width / 2;
100
+ const logicalY = view.y + view.height / 2;
101
+ const dx = (camera.camera.center.x - logicalX) * (1 - parallaxX);
102
+ const dy = (camera.camera.center.y - logicalY) * (1 - parallaxY);
103
+ const elements: ({ readonly translateX: number } | { readonly translateY: number })[] = [];
104
+ if (dx !== 0) {
105
+ elements.push({ translateX: dx });
106
+ }
107
+ if (dy !== 0) {
108
+ elements.push({ translateY: dy });
109
+ }
110
+ return elements;
111
+ }
112
+
113
+ /** The camera + viewport context provided by `GameWorld2D`. */
114
+ export interface GameWorldContextValue {
115
+ readonly viewport: SharedValue<ResolvedViewport2D | undefined>;
116
+ readonly camera: SharedValue<CameraCut2D | undefined> | undefined;
117
+ }
118
+
119
+ export const GameWorldContext = createContext<GameWorldContextValue | null>(null);
120
+
36
121
  export function GameWorld2D({
37
122
  viewport,
123
+ camera,
38
124
  children,
39
125
  }: {
40
126
  /** The resolved viewport shared value supplied to the renderer. */
41
127
  readonly viewport: SharedValue<ResolvedViewport2D | undefined>;
128
+ /** The presented camera shared value (T12.5); absent keeps the viewport-only path. */
129
+ readonly camera?: SharedValue<CameraCut2D | undefined> | undefined;
42
130
  readonly children: ReactNode;
43
131
  }) {
44
- const transform = useDerivedValue(() => viewportTransform(viewport.value));
45
- return <Group transform={transform as never}>{children}</Group>;
132
+ const transform = useDerivedValue(() =>
133
+ camera === undefined
134
+ ? viewportTransform(viewport.value)
135
+ : cameraViewportTransform2D(camera.value, viewport.value),
136
+ );
137
+ const context = { viewport, camera };
138
+ return (
139
+ <GameWorldContext.Provider value={context}>
140
+ <Group transform={transform as never}>{children}</Group>
141
+ </GameWorldContext.Provider>
142
+ );
143
+ }
144
+
145
+ /** Consume the world context; throws outside `GameWorld2D`. */
146
+ export function useGameWorldContext(): GameWorldContextValue {
147
+ const context = useContext(GameWorldContext);
148
+ if (context === null) {
149
+ throw new Error('GameLayer2D must be rendered inside a GameWorld2D');
150
+ }
151
+ return context;
46
152
  }
@@ -17,10 +17,13 @@ import { useRectBuffer, useRSXformBuffer } from '@shopify/react-native-skia';
17
17
  import type { LoadedImage, LoadedSpriteSheet } from '../../assets/types';
18
18
  import {
19
19
  computeSpriteRsxform,
20
- resolveSpriteFrameRect,
21
20
  spriteGroupCorrection,
22
- type SpriteTransformInput,
23
21
  } from './spriteTransform';
22
+ import {
23
+ applySpriteFrameSelection,
24
+ materializeSpriteSelection,
25
+ selectSpriteFrameRect,
26
+ } from './spriteSelection';
24
27
 
25
28
  export { resolveSpriteFrameRect, type SpriteFrameRect } from './spriteTransform';
26
29
 
@@ -82,91 +85,67 @@ export function Sprite({
82
85
  // Worklet-safe frame resolution: an explicit `frame` wins; otherwise the
83
86
  // clip + elapsed time select the frame (the clip/elapsed may be animated
84
87
  // shared values, so the resolution happens inside the rect modifier).
88
+ // The arithmetic lives in the shared selection contract — this modifier
89
+ // only adapts props into it (GS-ANIMATION-01).
85
90
  const resolveFrameRectWorklet = (
86
91
  rect: { setXYWH(x: number, y: number, width: number, height: number): void },
87
92
  ): void => {
88
93
  'worklet';
89
94
  const clipValue = typeof clip === 'string' ? clip : clip?.value;
90
95
  const elapsedValue = typeof elapsedMs === 'number' ? elapsedMs : elapsedMs?.value;
91
- let name: string | undefined = typeof frame === 'string' ? frame : frame?.value;
92
- if (name === undefined && source.descriptor.kind === 'sprite-sheet' && clipValue !== undefined) {
93
- const sheet = source as LoadedSpriteSheet;
94
- // R3: resolve the clip through the descriptor's animation table, then
95
- // the returned frame name through the frame rectangles below.
96
- const animation = sheet.descriptor.animations[clipValue];
97
- if (animation !== undefined && animation.frames.length > 0) {
98
- const duration = animation.frameDurationMs;
99
- const count = animation.frames.length;
100
- const index =
101
- animation.mode === 'once'
102
- ? Math.min(Math.floor((elapsedValue ?? 0) / duration), count - 1)
103
- : Math.floor((elapsedValue ?? 0) / duration) % count;
104
- name = animation.frames[index] ?? animation.frames[0];
105
- }
106
- }
107
- const frameRect =
108
- source.descriptor.kind === 'image'
109
- ? { x: 0, y: 0, width: (source as LoadedImage).width, height: (source as LoadedImage).height }
110
- : name === undefined
111
- ? undefined
112
- : (source as LoadedSpriteSheet).frames[name];
113
- if (frameRect === undefined) {
114
- if (name === undefined) {
115
- // RF4: the selection has not been published yet (scene mismatch or a
116
- // shared frame before its first value): present nothing, never throw.
117
- rect.setXYWH(0, 0, 0, 0);
118
- return;
119
- }
120
- throw new Error(
121
- `frame ${JSON.stringify(name)} does not belong to this sprite sheet (loaded frames: ${Object.keys((source as LoadedSpriteSheet).frames).join(', ')})`,
122
- );
123
- }
124
- rect.setXYWH(frameRect.x, frameRect.y, frameRect.width, frameRect.height);
125
- };
126
-
127
- const staticFrame = typeof frame === 'string' ? frame : undefined;
128
- const frameSize = useMemo(() => resolveSpriteFrameRect(source, staticFrame), [source, staticFrame]);
129
- const input: SpriteTransformInput = {
130
- x,
131
- y,
132
- rotation,
133
- scale,
134
- flipX,
135
- flipY,
136
- anchorX: anchor.x,
137
- anchorY: anchor.y,
138
- frameWidth: frameSize.width,
139
- frameHeight: frameSize.height,
96
+ const name: string | undefined = typeof frame === 'string' ? frame : frame?.value;
97
+ applySpriteFrameSelection(rect, source, {
98
+ ...(name === undefined ? {} : { frame: name }),
99
+ ...(clipValue === undefined ? {} : { clip: clipValue }),
100
+ ...(elapsedValue === undefined ? {} : { elapsedMs: elapsedValue }),
101
+ });
140
102
  };
141
103
 
142
104
  const rects = useRectBuffer(1, resolveFrameRectWorklet);
143
105
  const xforms = useRSXformBuffer(1, (xform) => {
144
106
  'worklet';
145
- // RF4: resolve the selected frame's rectangle and dimensions in the same
146
- // worklet update so the anchor math always uses the current frame size.
147
- const name = typeof frame === 'string' ? frame : frame?.value;
148
- let width = frameSize.width;
149
- let height = frameSize.height;
150
- if (name !== undefined && source.descriptor.kind === 'sprite-sheet') {
151
- const rect = (source as LoadedSpriteSheet).frames[name];
152
- if (rect !== undefined) {
153
- width = rect.width;
154
- height = rect.height;
155
- }
156
- }
107
+ // GS-SPRITE-03: the same shared selection the rect modifier resolves,
108
+ // so clip-driven frame changes reach the anchor math with current
109
+ // dimensions. Absent selection draws nothing; its transform is finite.
110
+ const resolved = selectSpriteFrameRect(
111
+ source,
112
+ materializeSpriteSelection(frame, clip, elapsedMs),
113
+ );
157
114
  const result = computeSpriteRsxform({
158
- ...input,
159
- frameWidth: width,
160
- frameHeight: height,
115
+ x,
116
+ y,
117
+ rotation,
118
+ scale,
119
+ flipX,
120
+ flipY,
121
+ anchorX: anchor.x,
122
+ anchorY: anchor.y,
123
+ frameWidth: resolved?.width ?? 0,
124
+ frameHeight: resolved?.height ?? 0,
161
125
  });
162
126
  xform.set(result.scos, result.ssin, result.tx, result.ty);
163
127
  });
164
- const groupTransform = useMemo(
165
- () => spriteGroupCorrection(input) as unknown as Parameters<typeof Group>[0]['transform'],
166
- // The correction reads animated values at draw time; the element list
167
- // identity is stable (values are shared-value reads inside the group).
168
- [anchor.x, anchor.y, frameSize.width, frameSize.height],
169
- );
128
+ // GS-SPRITE-01: the correction depends on position, rotation, scale,
129
+ // flips, and the live frame dimensions, so it is derived on the UI
130
+ // runtime from live values — never memoized from React-render reads.
131
+ const groupTransform = useDerivedValue(() => {
132
+ const resolved = selectSpriteFrameRect(
133
+ source,
134
+ materializeSpriteSelection(frame, clip, elapsedMs),
135
+ );
136
+ return spriteGroupCorrection({
137
+ x,
138
+ y,
139
+ rotation,
140
+ scale,
141
+ flipX,
142
+ flipY,
143
+ anchorX: anchor.x,
144
+ anchorY: anchor.y,
145
+ frameWidth: resolved?.width ?? 0,
146
+ frameHeight: resolved?.height ?? 0,
147
+ });
148
+ }, [x, y, rotation, scale, flipX, flipY, frame, clip, elapsedMs, source, anchor.x, anchor.y]);
170
149
  const colors = useMemo(() => (tint === undefined ? undefined : [tint]), [tint]);
171
150
 
172
151
  // The Skia Group has no `visible` prop: hiding is expressed as a combined
@@ -5,8 +5,9 @@
5
5
  * `Atlas` with fixed-capacity, UI-owned buffers. The normal path owns all
6
6
  * derived-value plumbing: `select` maps the committed snapshot to the item
7
7
  * array and `write` is a UI-runtime setter that writes transforms in place —
8
- * no per-frame allocation, no per-frame React, no author-written
9
- * `useDerivedValue` side effects.
8
+ * no per-frame React and no author-written `useDerivedValue` side effects.
9
+ * Per commit the select array, one policy object, and one RSXform result
10
+ * per written item are allocated; buffers themselves are never reallocated.
10
11
  *
11
12
  * Contract:
12
13
  * - `capacity` is fixed for the mounted batch; active count is explicit.
@@ -20,11 +21,17 @@ import { Atlas, type SkImage } from '@shopify/react-native-skia';
20
21
  import { useDerivedValue, type SharedValue } from 'react-native-reanimated';
21
22
  import { useRectBuffer, useRSXformBuffer } from '@shopify/react-native-skia';
22
23
 
24
+ import type { CameraCut2D } from '../../camera2d';
25
+ import type { Aabb2D } from '../../geometry/types';
23
26
  import type { CommitFrame } from '../../core/session/types';
27
+ import { batchVisibleBounds2D, intersectsBounds2D } from './batchVisibility';
28
+ import type { ResolvedViewport2D } from '../../viewport2d/types';
29
+ export { batchVisibleBounds2D, intersectsBounds2D };
24
30
  import type { SceneSnapshot } from '../../scene/types';
25
31
  import type { SceneMap } from '../../definition/types';
26
32
  import type { LoadedImage, LoadedSpriteSheet } from '../../assets/types';
27
33
  import { computeSpriteRsxform } from './spriteTransform';
34
+ import { selectSpriteFrameRect } from './spriteSelection';
28
35
  import { batchUpdatePolicy } from './spriteBatchPolicy';
29
36
 
30
37
  /** The per-item write surface handed to the author's `write` mapper. */
@@ -70,6 +77,22 @@ export interface SpriteBatchProps<
70
77
  readonly write: (write: SpriteBatchWrite, item: TItem, index: number) => void;
71
78
  /** Uniform anchor in [0, 1] relative to the selected frame. */
72
79
  readonly anchor?: { readonly x: number; readonly y: number };
80
+ /**
81
+ * Optional camera culling (T12.6): items whose authored world bounds fall
82
+ * outside the conservative visible region are hidden (zero-size slots)
83
+ * instead of drawn. Slot identity and capacity are unchanged; the
84
+ * simulation never knows culling happened. `bounds` maps an item to its
85
+ * world AABB and runs as a worklet on the UI runtime. A bounds record
86
+ * with non-finite values hides the item (fail-safe: invalid geometry is
87
+ * never drawn); padding must be finite and nonnegative (T12-F5).
88
+ */
89
+ readonly cull?: {
90
+ readonly camera: SharedValue<CameraCut2D | undefined>;
91
+ readonly viewport: SharedValue<ResolvedViewport2D | undefined>;
92
+ readonly bounds: (item: TItem) => Aabb2D;
93
+ /** Optional world-space padding around the visible region. */
94
+ readonly padding?: number;
95
+ };
73
96
  }
74
97
 
75
98
  function frameRectOf(
@@ -77,11 +100,13 @@ function frameRectOf(
77
100
  frame: string,
78
101
  ): { x: number; y: number; width: number; height: number } | undefined {
79
102
  'worklet';
80
- if (source.descriptor.kind === 'image') {
81
- const image = source as LoadedImage;
82
- return { x: 0, y: 0, width: image.width, height: image.height };
103
+ // GS-SPRITE-04: the shared selection contract resolves the rectangle, so
104
+ // unknown frames fail with the same actionable error as retained sprites.
105
+ const resolved = selectSpriteFrameRect(source, { frame });
106
+ if (resolved === undefined) {
107
+ throw new Error(`frame ${JSON.stringify(frame)} does not belong to this sprite sheet`);
83
108
  }
84
- return (source as LoadedSpriteSheet).frames[frame];
109
+ return resolved;
85
110
  }
86
111
 
87
112
  export function SpriteBatch<
@@ -97,6 +122,7 @@ export function SpriteBatch<
97
122
  select,
98
123
  write,
99
124
  anchor = { x: 0, y: 0 },
125
+ cull,
100
126
  }: SpriteBatchProps<TScenes, TSceneName, TItem>) {
101
127
  const image = source.image as SkImage;
102
128
  if (!Number.isInteger(capacity) || capacity <= 0) {
@@ -104,6 +130,14 @@ export function SpriteBatch<
104
130
  `SpriteBatch capacity must be a positive integer, got ${String(capacity)}`,
105
131
  );
106
132
  }
133
+ // T12-F5: culling padding is validated ONCE at the React boundary; the UI
134
+ // worklet consumes a trusted finite nonnegative scalar.
135
+ const cullPadding = cull?.padding ?? 0;
136
+ if (!Number.isFinite(cullPadding) || cullPadding < 0) {
137
+ throw new RangeError(
138
+ `SpriteBatch cull.padding must be a finite nonnegative number, got ${String(cullPadding)}`,
139
+ );
140
+ }
107
141
  const rects = useRectBuffer(capacity, (rect) => {
108
142
  'worklet';
109
143
  rect.setXYWH(0, 0, 0, 0);
@@ -119,9 +153,11 @@ export function SpriteBatch<
119
153
  () => ({
120
154
  set: (index, frame, x, y, rotation, scale, visible = true) => {
121
155
  'worklet';
122
- if (index < 0 || index >= capacity) {
156
+ // GS-SPRITE-04: the author-exposed index is validated as an integer
157
+ // slot — a fractional index would silently miss every buffer slot.
158
+ if (!Number.isInteger(index) || index < 0 || index >= capacity) {
123
159
  throw new Error(
124
- `SpriteBatch write index ${index} is outside the capacity ${capacity}`,
160
+ `SpriteBatch write index ${String(index)} is outside the capacity ${capacity}`,
125
161
  );
126
162
  }
127
163
  const rectSlot = rects.value[index];
@@ -161,8 +197,10 @@ export function SpriteBatch<
161
197
 
162
198
  // The batch's own UI mapper: one derived value reads the committed
163
199
  // snapshot, runs the author's select + write per item, and reports the
164
- // active count. Buffers are mutated in place; no objects are allocated
165
- // per item per frame beyond the item array the select returns.
200
+ // active count. Buffers are mutated in place with no per-frame React;
201
+ // per commit the select array, one policy object, and one RSXform result
202
+ // per written item are allocated (GS-SPRITE-04: scalar writers stay
203
+ // unjustified without a benchmark showing this matters).
166
204
  const activeCount = useDerivedValue(() => {
167
205
  'worklet';
168
206
  const envelope = commit.value;
@@ -182,22 +220,36 @@ export function SpriteBatch<
182
220
  alpha: alpha.value,
183
221
  });
184
222
  const policy = batchUpdatePolicy(items.length, capacity, __DEV__);
185
- if (policy.overflow) {
186
- // RF8: production never crashes the UI runtime for ordinary data
187
- // growth: hide the overflowing items.
188
- for (let index = capacity; index < items.length; index += 1) {
223
+ // GS-SPRITE-04: no overflow loop — `policy.activeCount` already clamps
224
+ // production writes to capacity, and every buffer slot past capacity is
225
+ // absent by construction, so iterating [capacity, items.length) could
226
+ // only add unbounded dead work.
227
+ const count = policy.activeCount;
228
+ // T12.6 + T12-F5: culling hides off-screen slots in place, and
229
+ // authored writes run ONLY through `policy.activeCount`. In production
230
+ // an overflowing item (index >= capacity) is never written and never
231
+ // indexes a buffer — the [count, capacity) hide loop below clears the
232
+ // unused tail. The visible bounds are computed once per commit from the
233
+ // PRESENTED camera; hidden slots are cleared directly (zero size)
234
+ // without touching the author's write or reallocating buffers, so slot
235
+ // identity is stable across camera moves.
236
+ const visible =
237
+ cull === undefined
238
+ ? undefined
239
+ : batchVisibleBounds2D(cull.camera.value, cull.viewport.value, cullPadding);
240
+ for (let index = 0; index < count; index += 1) {
241
+ const item = items[index];
242
+ if (item === undefined) {
243
+ continue;
244
+ }
245
+ if (visible !== undefined && !intersectsBounds2D(cull!.bounds(item), visible)) {
189
246
  const slot = rects.value[index];
190
247
  if (slot !== undefined) {
191
248
  slot.setXYWH(0, 0, 0, 0);
192
249
  }
250
+ continue;
193
251
  }
194
- }
195
- const count = policy.activeCount;
196
- for (let index = 0; index < items.length; index += 1) {
197
- const item = items[index];
198
- if (item !== undefined) {
199
- write(writeApi, item, index);
200
- }
252
+ write(writeApi, item, index);
201
253
  }
202
254
  // Hide every inactive slot.
203
255
  for (let index = count; index < capacity; index += 1) {
@@ -207,7 +259,7 @@ export function SpriteBatch<
207
259
  }
208
260
  }
209
261
  return count;
210
- }, [commit, alpha, scene, select, write, writeApi]);
262
+ }, [commit, alpha, scene, select, write, writeApi, cull, cullPadding]);
211
263
 
212
264
  void activeCount;
213
265
 
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Batch culling math (T12.6, T12-F5) — pure and worklet-safe, with no React
3
+ * imports, so the benchmark and headless tests can import them directly.
4
+ */
5
+ import type { CameraCut2D } from '../../camera2d';
6
+ import { rotatedHalfExtents2D } from '../../camera2d/extents';
7
+ import type { Aabb2D } from '../../geometry/types';
8
+ import type { ResolvedViewport2D } from '../../viewport2d/types';
9
+
10
+ /**
11
+ * Conservative visible bounds for batch culling (T12.6).
12
+ *
13
+ * Worklet-safe inline version of the headless `paddedCameraBounds2D` —
14
+ * the presented camera is already validated at the public boundary, so the
15
+ * per-frame path allocates nothing and validates nothing.
16
+ */
17
+ export function batchVisibleBounds2D(
18
+ camera: CameraCut2D | undefined,
19
+ viewport: ResolvedViewport2D | undefined,
20
+ padding: number,
21
+ ): Aabb2D | undefined {
22
+ 'worklet';
23
+ if (camera === undefined || viewport === undefined) {
24
+ return undefined;
25
+ }
26
+ const view = viewport.visibleLogicalBounds;
27
+ const extent = rotatedHalfExtents2D(
28
+ view.width / 2 / camera.camera.zoom,
29
+ view.height / 2 / camera.camera.zoom,
30
+ camera.camera.rotationRadians,
31
+ );
32
+ const extentX = extent.x + padding;
33
+ const extentY = extent.y + padding;
34
+ return {
35
+ x: camera.camera.center.x - extentX,
36
+ y: camera.camera.center.y - extentY,
37
+ width: extentX * 2,
38
+ height: extentY * 2,
39
+ };
40
+ }
41
+
42
+ function isFiniteBounds(bounds: Aabb2D): boolean {
43
+ 'worklet';
44
+ return (
45
+ Number.isFinite(bounds.x) &&
46
+ Number.isFinite(bounds.y) &&
47
+ Number.isFinite(bounds.width) &&
48
+ Number.isFinite(bounds.height) &&
49
+ bounds.width >= 0 &&
50
+ bounds.height >= 0
51
+ );
52
+ }
53
+
54
+ /** Axis-aligned intersection test, worklet-safe (no validation).
55
+ *
56
+ * Inclusive comparisons, matching the public `intersectsAabbAabb2D`
57
+ * contract (T12-F5): exact boundary contact IS an intersection, so a
58
+ * sprite touching the camera edge is never culled.
59
+ *
60
+ * T12-RF6 malformed-bounds fail-safe: any non-finite field or negative
61
+ * size in EITHER rect hides the item (returns false) before the
62
+ * intersection test — invalid geometry is never drawn. Scalar and
63
+ * allocation-free; no structured error construction on the UI path.
64
+ */
65
+ export function intersectsBounds2D(first: Aabb2D, second: Aabb2D): boolean {
66
+ 'worklet';
67
+ if (!isFiniteBounds(first) || !isFiniteBounds(second)) {
68
+ return false;
69
+ }
70
+ return (
71
+ first.x <= second.x + second.width &&
72
+ first.x + first.width >= second.x &&
73
+ first.y <= second.y + second.height &&
74
+ first.y + first.height >= second.y
75
+ );
76
+ }