@codexo/exojs 0.8.0 → 0.8.3

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 (498) hide show
  1. package/CHANGELOG.md +390 -208
  2. package/README.md +19 -19
  3. package/dist/esm/animation/Easing.js +13 -21
  4. package/dist/esm/animation/Easing.js.map +1 -1
  5. package/dist/esm/animation/Tween.d.ts +3 -3
  6. package/dist/esm/animation/Tween.js +7 -5
  7. package/dist/esm/animation/Tween.js.map +1 -1
  8. package/dist/esm/animation/TweenManager.js +1 -1
  9. package/dist/esm/animation/TweenManager.js.map +1 -1
  10. package/dist/esm/animation/types.js.map +1 -1
  11. package/dist/esm/audio/AbstractMedia.d.ts +1 -1
  12. package/dist/esm/audio/AbstractMedia.js +1 -1
  13. package/dist/esm/audio/AbstractMedia.js.map +1 -1
  14. package/dist/esm/audio/AudioAnalyser.d.ts +37 -1
  15. package/dist/esm/audio/AudioAnalyser.js +150 -2
  16. package/dist/esm/audio/AudioAnalyser.js.map +1 -1
  17. package/dist/esm/audio/AudioBus.d.ts +1 -1
  18. package/dist/esm/audio/AudioBus.js.map +1 -1
  19. package/dist/esm/audio/AudioFilter.js +3 -1
  20. package/dist/esm/audio/AudioFilter.js.map +1 -1
  21. package/dist/esm/audio/AudioListener.d.ts +1 -1
  22. package/dist/esm/audio/AudioListener.js +5 -3
  23. package/dist/esm/audio/AudioListener.js.map +1 -1
  24. package/dist/esm/audio/AudioManager.js.map +1 -1
  25. package/dist/esm/audio/BeatDetector.d.ts +66 -4
  26. package/dist/esm/audio/BeatDetector.js +145 -44
  27. package/dist/esm/audio/BeatDetector.js.map +1 -1
  28. package/dist/esm/audio/Envelope.d.ts +1 -1
  29. package/dist/esm/audio/Envelope.js +2 -2
  30. package/dist/esm/audio/Envelope.js.map +1 -1
  31. package/dist/esm/audio/Music.d.ts +1 -1
  32. package/dist/esm/audio/Music.js +1 -1
  33. package/dist/esm/audio/Music.js.map +1 -1
  34. package/dist/esm/audio/OscillatorSound.d.ts +2 -2
  35. package/dist/esm/audio/OscillatorSound.js.map +1 -1
  36. package/dist/esm/audio/Sound.d.ts +40 -2
  37. package/dist/esm/audio/Sound.js +69 -9
  38. package/dist/esm/audio/Sound.js.map +1 -1
  39. package/dist/esm/audio/audio-context.js +1 -1
  40. package/dist/esm/audio/audio-context.js.map +1 -1
  41. package/dist/esm/audio/crossFade.js +1 -1
  42. package/dist/esm/audio/crossFade.js.map +1 -1
  43. package/dist/esm/audio/dsp/mel.d.ts +2 -2
  44. package/dist/esm/audio/dsp/mel.js +70 -0
  45. package/dist/esm/audio/dsp/mel.js.map +1 -0
  46. package/dist/esm/audio/dsp/tempogram.d.ts +2 -2
  47. package/dist/esm/audio/filters/ChorusFilter.js +12 -4
  48. package/dist/esm/audio/filters/ChorusFilter.js.map +1 -1
  49. package/dist/esm/audio/filters/CompressorFilter.d.ts +9 -0
  50. package/dist/esm/audio/filters/CompressorFilter.js +11 -0
  51. package/dist/esm/audio/filters/CompressorFilter.js.map +1 -1
  52. package/dist/esm/audio/filters/DelayFilter.js.map +1 -1
  53. package/dist/esm/audio/filters/DuckingFilter.d.ts +1 -1
  54. package/dist/esm/audio/filters/DuckingFilter.js +13 -5
  55. package/dist/esm/audio/filters/DuckingFilter.js.map +1 -1
  56. package/dist/esm/audio/filters/EqualizerFilter.js.map +1 -1
  57. package/dist/esm/audio/filters/GranularFilter.js +30 -14
  58. package/dist/esm/audio/filters/GranularFilter.js.map +1 -1
  59. package/dist/esm/audio/filters/HighpassFilter.js.map +1 -1
  60. package/dist/esm/audio/filters/LowpassFilter.js.map +1 -1
  61. package/dist/esm/audio/filters/PitchShiftFilter.js +14 -10
  62. package/dist/esm/audio/filters/PitchShiftFilter.js.map +1 -1
  63. package/dist/esm/audio/filters/ReverbFilter.js.map +1 -1
  64. package/dist/esm/audio/filters/VocoderFilter.d.ts +2 -2
  65. package/dist/esm/audio/filters/VocoderFilter.js +20 -12
  66. package/dist/esm/audio/filters/VocoderFilter.js.map +1 -1
  67. package/dist/esm/audio/filters/WorkletFilter.js +5 -6
  68. package/dist/esm/audio/filters/WorkletFilter.js.map +1 -1
  69. package/dist/esm/audio/filters/index.d.ts +7 -7
  70. package/dist/esm/audio/index.d.ts +9 -9
  71. package/dist/esm/audio/worklet/registerWorklet.js +7 -3
  72. package/dist/esm/audio/worklet/registerWorklet.js.map +1 -1
  73. package/dist/esm/core/Application.d.ts +13 -13
  74. package/dist/esm/core/Application.js +24 -16
  75. package/dist/esm/core/Application.js.map +1 -1
  76. package/dist/esm/core/Bounds.d.ts +1 -1
  77. package/dist/esm/core/Bounds.js +1 -3
  78. package/dist/esm/core/Bounds.js.map +1 -1
  79. package/dist/esm/core/Clock.js +1 -1
  80. package/dist/esm/core/Clock.js.map +1 -1
  81. package/dist/esm/core/Color.js +2 -5
  82. package/dist/esm/core/Color.js.map +1 -1
  83. package/dist/esm/core/Scene.d.ts +10 -10
  84. package/dist/esm/core/Scene.js +1 -1
  85. package/dist/esm/core/Scene.js.map +1 -1
  86. package/dist/esm/core/SceneManager.d.ts +4 -4
  87. package/dist/esm/core/SceneManager.js +39 -33
  88. package/dist/esm/core/SceneManager.js.map +1 -1
  89. package/dist/esm/core/SceneNode.d.ts +8 -8
  90. package/dist/esm/core/SceneNode.js +39 -29
  91. package/dist/esm/core/SceneNode.js.map +1 -1
  92. package/dist/esm/core/Signal.d.ts +3 -3
  93. package/dist/esm/core/Signal.js +3 -3
  94. package/dist/esm/core/Signal.js.map +1 -1
  95. package/dist/esm/core/Time.js +6 -6
  96. package/dist/esm/core/Time.js.map +1 -1
  97. package/dist/esm/core/Timer.d.ts +1 -1
  98. package/dist/esm/core/Timer.js +1 -1
  99. package/dist/esm/core/Timer.js.map +1 -1
  100. package/dist/esm/core/capabilities.js +2 -4
  101. package/dist/esm/core/capabilities.js.map +1 -1
  102. package/dist/esm/core/index.d.ts +2 -2
  103. package/dist/esm/core/utils.d.ts +4 -4
  104. package/dist/esm/core/utils.js +10 -10
  105. package/dist/esm/core/utils.js.map +1 -1
  106. package/dist/esm/debug/BoundingBoxesLayer.d.ts +3 -3
  107. package/dist/esm/debug/BoundingBoxesLayer.js +6 -13
  108. package/dist/esm/debug/BoundingBoxesLayer.js.map +1 -1
  109. package/dist/esm/debug/DebugLayer.d.ts +1 -1
  110. package/dist/esm/debug/DebugLayer.js.map +1 -1
  111. package/dist/esm/debug/DebugOverlay.d.ts +2 -2
  112. package/dist/esm/debug/DebugOverlay.js +2 -2
  113. package/dist/esm/debug/DebugOverlay.js.map +1 -1
  114. package/dist/esm/debug/HitTestLayer.d.ts +3 -3
  115. package/dist/esm/debug/HitTestLayer.js +3 -10
  116. package/dist/esm/debug/HitTestLayer.js.map +1 -1
  117. package/dist/esm/debug/PerformanceLayer.d.ts +2 -2
  118. package/dist/esm/debug/PerformanceLayer.js +6 -6
  119. package/dist/esm/debug/PerformanceLayer.js.map +1 -1
  120. package/dist/esm/debug/PointerStackLayer.d.ts +3 -3
  121. package/dist/esm/debug/PointerStackLayer.js +3 -3
  122. package/dist/esm/debug/PointerStackLayer.js.map +1 -1
  123. package/dist/esm/debug/RenderPassInspectorLayer.d.ts +71 -0
  124. package/dist/esm/debug/RenderPassInspectorLayer.js +201 -0
  125. package/dist/esm/debug/RenderPassInspectorLayer.js.map +1 -0
  126. package/dist/esm/debug/index.d.ts +4 -3
  127. package/dist/esm/debug/index.js +4 -3
  128. package/dist/esm/debug/index.js.map +1 -1
  129. package/dist/esm/index.d.ts +1 -1
  130. package/dist/esm/index.js +101 -98
  131. package/dist/esm/index.js.map +1 -1
  132. package/dist/esm/input/ArcadeStickGamepadMapping.js.map +1 -1
  133. package/dist/esm/input/GameCubeGamepadMapping.d.ts +1 -1
  134. package/dist/esm/input/GameCubeGamepadMapping.js +1 -1
  135. package/dist/esm/input/GameCubeGamepadMapping.js.map +1 -1
  136. package/dist/esm/input/Gamepad.d.ts +7 -7
  137. package/dist/esm/input/Gamepad.js +10 -6
  138. package/dist/esm/input/Gamepad.js.map +1 -1
  139. package/dist/esm/input/GamepadAxis.js +1 -1
  140. package/dist/esm/input/GamepadAxis.js.map +1 -1
  141. package/dist/esm/input/GamepadButton.js +1 -1
  142. package/dist/esm/input/GamepadButton.js.map +1 -1
  143. package/dist/esm/input/GamepadDefinitions.d.ts +4 -4
  144. package/dist/esm/input/GamepadDefinitions.js +12 -14
  145. package/dist/esm/input/GamepadDefinitions.js.map +1 -1
  146. package/dist/esm/input/GamepadMapping.d.ts +5 -5
  147. package/dist/esm/input/GamepadMapping.js.map +1 -1
  148. package/dist/esm/input/GamepadPromptLayouts.d.ts +2 -2
  149. package/dist/esm/input/GamepadPromptLayouts.js +8 -8
  150. package/dist/esm/input/GamepadPromptLayouts.js.map +1 -1
  151. package/dist/esm/input/GenericDualAnalogGamepadMapping.js.map +1 -1
  152. package/dist/esm/input/GestureRecognizer.d.ts +1 -1
  153. package/dist/esm/input/GestureRecognizer.js.map +1 -1
  154. package/dist/esm/input/InputBinding.d.ts +3 -3
  155. package/dist/esm/input/InputBinding.js.map +1 -1
  156. package/dist/esm/input/InputManager.d.ts +9 -9
  157. package/dist/esm/input/InputManager.js +25 -16
  158. package/dist/esm/input/InputManager.js.map +1 -1
  159. package/dist/esm/input/InteractionEvent.d.ts +1 -1
  160. package/dist/esm/input/InteractionEvent.js.map +1 -1
  161. package/dist/esm/input/InteractionManager.d.ts +2 -2
  162. package/dist/esm/input/InteractionManager.js +25 -16
  163. package/dist/esm/input/InteractionManager.js.map +1 -1
  164. package/dist/esm/input/JoyConLeftGamepadMapping.js.map +1 -1
  165. package/dist/esm/input/JoyConRightGamepadMapping.js.map +1 -1
  166. package/dist/esm/input/PlayStationGamepadMapping.d.ts +1 -1
  167. package/dist/esm/input/PlayStationGamepadMapping.js +1 -1
  168. package/dist/esm/input/PlayStationGamepadMapping.js.map +1 -1
  169. package/dist/esm/input/Pointer.d.ts +2 -2
  170. package/dist/esm/input/Pointer.js +6 -6
  171. package/dist/esm/input/Pointer.js.map +1 -1
  172. package/dist/esm/input/SteamControllerGamepadMapping.d.ts +1 -1
  173. package/dist/esm/input/SteamControllerGamepadMapping.js +1 -1
  174. package/dist/esm/input/SteamControllerGamepadMapping.js.map +1 -1
  175. package/dist/esm/input/SteamDeckGamepadMapping.js.map +1 -1
  176. package/dist/esm/input/SwitchProGamepadMapping.d.ts +1 -1
  177. package/dist/esm/input/SwitchProGamepadMapping.js +1 -1
  178. package/dist/esm/input/SwitchProGamepadMapping.js.map +1 -1
  179. package/dist/esm/input/XboxGamepadMapping.d.ts +1 -1
  180. package/dist/esm/input/XboxGamepadMapping.js +1 -1
  181. package/dist/esm/input/XboxGamepadMapping.js.map +1 -1
  182. package/dist/esm/input/index.d.ts +16 -16
  183. package/dist/esm/input/interaction-hooks.js.map +1 -1
  184. package/dist/esm/input/types.js.map +1 -1
  185. package/dist/esm/math/AbstractVector.js +8 -9
  186. package/dist/esm/math/AbstractVector.js.map +1 -1
  187. package/dist/esm/math/Circle.d.ts +5 -5
  188. package/dist/esm/math/Circle.js +33 -21
  189. package/dist/esm/math/Circle.js.map +1 -1
  190. package/dist/esm/math/Collision.d.ts +2 -2
  191. package/dist/esm/math/Collision.js.map +1 -1
  192. package/dist/esm/math/Ellipse.d.ts +5 -5
  193. package/dist/esm/math/Ellipse.js +28 -19
  194. package/dist/esm/math/Ellipse.js.map +1 -1
  195. package/dist/esm/math/Flags.d.ts +4 -4
  196. package/dist/esm/math/Flags.js.map +1 -1
  197. package/dist/esm/math/Interval.js.map +1 -1
  198. package/dist/esm/math/Line.d.ts +5 -5
  199. package/dist/esm/math/Line.js +23 -15
  200. package/dist/esm/math/Line.js.map +1 -1
  201. package/dist/esm/math/Matrix.js +14 -16
  202. package/dist/esm/math/Matrix.js.map +1 -1
  203. package/dist/esm/math/ObservableSize.js.map +1 -1
  204. package/dist/esm/math/ObservableVector.d.ts +1 -1
  205. package/dist/esm/math/ObservableVector.js.map +1 -1
  206. package/dist/esm/math/PolarVector.js.map +1 -1
  207. package/dist/esm/math/Polygon.d.ts +11 -11
  208. package/dist/esm/math/Polygon.js +37 -26
  209. package/dist/esm/math/Polygon.js.map +1 -1
  210. package/dist/esm/math/PolygonLike.d.ts +1 -1
  211. package/dist/esm/math/Quadtree.js +2 -8
  212. package/dist/esm/math/Quadtree.js.map +1 -1
  213. package/dist/esm/math/Random.js +5 -5
  214. package/dist/esm/math/Random.js.map +1 -1
  215. package/dist/esm/math/Rectangle.d.ts +4 -4
  216. package/dist/esm/math/Rectangle.js +59 -41
  217. package/dist/esm/math/Rectangle.js.map +1 -1
  218. package/dist/esm/math/Segment.d.ts +1 -1
  219. package/dist/esm/math/Segment.js +4 -4
  220. package/dist/esm/math/Segment.js.map +1 -1
  221. package/dist/esm/math/ShapeLike.d.ts +1 -1
  222. package/dist/esm/math/Size.js +1 -2
  223. package/dist/esm/math/Size.js.map +1 -1
  224. package/dist/esm/math/Vector.d.ts +4 -4
  225. package/dist/esm/math/Vector.js +19 -13
  226. package/dist/esm/math/Vector.js.map +1 -1
  227. package/dist/esm/math/collision-detection.d.ts +3 -3
  228. package/dist/esm/math/collision-detection.js +49 -49
  229. package/dist/esm/math/collision-detection.js.map +1 -1
  230. package/dist/esm/math/collision-primitives.d.ts +8 -8
  231. package/dist/esm/math/collision-primitives.js +27 -33
  232. package/dist/esm/math/collision-primitives.js.map +1 -1
  233. package/dist/esm/math/geometry.d.ts +3 -3
  234. package/dist/esm/math/geometry.js +55 -48
  235. package/dist/esm/math/geometry.js.map +1 -1
  236. package/dist/esm/math/index.d.ts +16 -16
  237. package/dist/esm/math/swept-collision.d.ts +3 -3
  238. package/dist/esm/math/swept-collision.js +5 -8
  239. package/dist/esm/math/swept-collision.js.map +1 -1
  240. package/dist/esm/math/triangulate.js +34 -24
  241. package/dist/esm/math/triangulate.js.map +1 -1
  242. package/dist/esm/math/utils.d.ts +2 -2
  243. package/dist/esm/math/utils.js +7 -7
  244. package/dist/esm/math/utils.js.map +1 -1
  245. package/dist/esm/particles/ParticleSystem.d.ts +9 -9
  246. package/dist/esm/particles/ParticleSystem.js +29 -29
  247. package/dist/esm/particles/ParticleSystem.js.map +1 -1
  248. package/dist/esm/particles/distributions/BoxArea.js.map +1 -1
  249. package/dist/esm/particles/distributions/CircleArea.js.map +1 -1
  250. package/dist/esm/particles/distributions/ConeDirection.js.map +1 -1
  251. package/dist/esm/particles/distributions/Constant.js.map +1 -1
  252. package/dist/esm/particles/distributions/Curve.d.ts +1 -1
  253. package/dist/esm/particles/distributions/Curve.js.map +1 -1
  254. package/dist/esm/particles/distributions/Gradient.d.ts +1 -1
  255. package/dist/esm/particles/distributions/Gradient.js +1 -1
  256. package/dist/esm/particles/distributions/Gradient.js.map +1 -1
  257. package/dist/esm/particles/distributions/LineSegment.js.map +1 -1
  258. package/dist/esm/particles/distributions/Range.js.map +1 -1
  259. package/dist/esm/particles/distributions/VectorRange.js.map +1 -1
  260. package/dist/esm/particles/distributions/index.d.ts +9 -9
  261. package/dist/esm/particles/gpu/ParticleGpuState.d.ts +3 -3
  262. package/dist/esm/particles/gpu/ParticleGpuState.js +48 -21
  263. package/dist/esm/particles/gpu/ParticleGpuState.js.map +1 -1
  264. package/dist/esm/particles/index.d.ts +1 -1
  265. package/dist/esm/particles/modules/AlphaFadeOverLifetime.d.ts +2 -2
  266. package/dist/esm/particles/modules/AlphaFadeOverLifetime.js.map +1 -1
  267. package/dist/esm/particles/modules/ApplyForce.d.ts +1 -1
  268. package/dist/esm/particles/modules/ApplyForce.js.map +1 -1
  269. package/dist/esm/particles/modules/AttractToPoint.d.ts +1 -1
  270. package/dist/esm/particles/modules/AttractToPoint.js.map +1 -1
  271. package/dist/esm/particles/modules/BurstSpawn.d.ts +4 -4
  272. package/dist/esm/particles/modules/BurstSpawn.js +2 -2
  273. package/dist/esm/particles/modules/BurstSpawn.js.map +1 -1
  274. package/dist/esm/particles/modules/ColorOverLifetime.d.ts +2 -2
  275. package/dist/esm/particles/modules/ColorOverLifetime.js +1 -1
  276. package/dist/esm/particles/modules/ColorOverLifetime.js.map +1 -1
  277. package/dist/esm/particles/modules/ColorOverSpeed.d.ts +2 -2
  278. package/dist/esm/particles/modules/ColorOverSpeed.js +1 -1
  279. package/dist/esm/particles/modules/ColorOverSpeed.js.map +1 -1
  280. package/dist/esm/particles/modules/DeathModule.js.map +1 -1
  281. package/dist/esm/particles/modules/Drag.d.ts +1 -1
  282. package/dist/esm/particles/modules/Drag.js +1 -3
  283. package/dist/esm/particles/modules/Drag.js.map +1 -1
  284. package/dist/esm/particles/modules/OrbitalForce.d.ts +1 -1
  285. package/dist/esm/particles/modules/OrbitalForce.js.map +1 -1
  286. package/dist/esm/particles/modules/RateSpawn.d.ts +3 -3
  287. package/dist/esm/particles/modules/RateSpawn.js +2 -2
  288. package/dist/esm/particles/modules/RateSpawn.js.map +1 -1
  289. package/dist/esm/particles/modules/RepelFromPoint.d.ts +1 -1
  290. package/dist/esm/particles/modules/RepelFromPoint.js.map +1 -1
  291. package/dist/esm/particles/modules/RotateOverLifetime.d.ts +1 -1
  292. package/dist/esm/particles/modules/RotateOverLifetime.js +1 -3
  293. package/dist/esm/particles/modules/RotateOverLifetime.js.map +1 -1
  294. package/dist/esm/particles/modules/ScaleOverLifetime.d.ts +2 -2
  295. package/dist/esm/particles/modules/ScaleOverLifetime.js.map +1 -1
  296. package/dist/esm/particles/modules/SpawnModule.js.map +1 -1
  297. package/dist/esm/particles/modules/SpawnOnDeath.d.ts +1 -1
  298. package/dist/esm/particles/modules/SpawnOnDeath.js.map +1 -1
  299. package/dist/esm/particles/modules/Turbulence.d.ts +1 -1
  300. package/dist/esm/particles/modules/Turbulence.js.map +1 -1
  301. package/dist/esm/particles/modules/UpdateModule.js.map +1 -1
  302. package/dist/esm/particles/modules/VelocityOverLifetime.d.ts +2 -2
  303. package/dist/esm/particles/modules/VelocityOverLifetime.js.map +1 -1
  304. package/dist/esm/particles/modules/WgslContribution.d.ts +3 -3
  305. package/dist/esm/particles/modules/WgslContribution.js.map +1 -1
  306. package/dist/esm/particles/modules/index.d.ts +17 -17
  307. package/dist/esm/rendering/CallbackRenderPass.js.map +1 -1
  308. package/dist/esm/rendering/Container.d.ts +2 -2
  309. package/dist/esm/rendering/Container.js +10 -11
  310. package/dist/esm/rendering/Container.js.map +1 -1
  311. package/dist/esm/rendering/Drawable.js.map +1 -1
  312. package/dist/esm/rendering/RenderBackend.d.ts +6 -6
  313. package/dist/esm/rendering/RenderBackendType.js.map +1 -1
  314. package/dist/esm/rendering/RenderNode.d.ts +10 -10
  315. package/dist/esm/rendering/RenderNode.js +31 -31
  316. package/dist/esm/rendering/RenderNode.js.map +1 -1
  317. package/dist/esm/rendering/RenderStats.js.map +1 -1
  318. package/dist/esm/rendering/RenderTarget.d.ts +2 -2
  319. package/dist/esm/rendering/RenderTarget.js +5 -5
  320. package/dist/esm/rendering/RenderTarget.js.map +1 -1
  321. package/dist/esm/rendering/RenderTargetPass.d.ts +3 -3
  322. package/dist/esm/rendering/RenderTargetPass.js.map +1 -1
  323. package/dist/esm/rendering/Renderer.d.ts +2 -2
  324. package/dist/esm/rendering/RendererRegistry.d.ts +3 -3
  325. package/dist/esm/rendering/RendererRegistry.js +2 -3
  326. package/dist/esm/rendering/RendererRegistry.js.map +1 -1
  327. package/dist/esm/rendering/View.d.ts +3 -3
  328. package/dist/esm/rendering/View.js +17 -20
  329. package/dist/esm/rendering/View.js.map +1 -1
  330. package/dist/esm/rendering/filters/BlurFilter.d.ts +1 -1
  331. package/dist/esm/rendering/filters/BlurFilter.js +4 -9
  332. package/dist/esm/rendering/filters/BlurFilter.js.map +1 -1
  333. package/dist/esm/rendering/filters/ColorFilter.d.ts +1 -1
  334. package/dist/esm/rendering/filters/ColorFilter.js +3 -9
  335. package/dist/esm/rendering/filters/ColorFilter.js.map +1 -1
  336. package/dist/esm/rendering/filters/Filter.d.ts +1 -1
  337. package/dist/esm/rendering/filters/Filter.js.map +1 -1
  338. package/dist/esm/rendering/filters/LutFilter.d.ts +87 -0
  339. package/dist/esm/rendering/filters/LutFilter.js +261 -0
  340. package/dist/esm/rendering/filters/LutFilter.js.map +1 -0
  341. package/dist/esm/rendering/filters/WebGl2ShaderFilter.d.ts +2 -2
  342. package/dist/esm/rendering/filters/WebGl2ShaderFilter.js +7 -14
  343. package/dist/esm/rendering/filters/WebGl2ShaderFilter.js.map +1 -1
  344. package/dist/esm/rendering/filters/WebGpuShaderFilter.d.ts +1 -1
  345. package/dist/esm/rendering/filters/WebGpuShaderFilter.js +16 -11
  346. package/dist/esm/rendering/filters/WebGpuShaderFilter.js.map +1 -1
  347. package/dist/esm/rendering/index.d.ts +30 -27
  348. package/dist/esm/rendering/mesh/Mesh.d.ts +6 -1
  349. package/dist/esm/rendering/mesh/Mesh.js +3 -1
  350. package/dist/esm/rendering/mesh/Mesh.js.map +1 -1
  351. package/dist/esm/rendering/mesh/MeshShader.d.ts +183 -0
  352. package/dist/esm/rendering/mesh/MeshShader.js +231 -0
  353. package/dist/esm/rendering/mesh/MeshShader.js.map +1 -0
  354. package/dist/esm/rendering/primitives/Graphics.d.ts +3 -3
  355. package/dist/esm/rendering/primitives/Graphics.js +12 -12
  356. package/dist/esm/rendering/primitives/Graphics.js.map +1 -1
  357. package/dist/esm/rendering/shader/Shader.js.map +1 -1
  358. package/dist/esm/rendering/shader/ShaderAttribute.js.map +1 -1
  359. package/dist/esm/rendering/shader/ShaderUniform.js.map +1 -1
  360. package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.js +6 -8
  361. package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.js.map +1 -1
  362. package/dist/esm/rendering/sprite/AnimatedSprite.d.ts +3 -3
  363. package/dist/esm/rendering/sprite/AnimatedSprite.js.map +1 -1
  364. package/dist/esm/rendering/sprite/Sprite.d.ts +4 -4
  365. package/dist/esm/rendering/sprite/Sprite.js +51 -35
  366. package/dist/esm/rendering/sprite/Sprite.js.map +1 -1
  367. package/dist/esm/rendering/sprite/Spritesheet.d.ts +5 -9
  368. package/dist/esm/rendering/sprite/Spritesheet.js +1 -1
  369. package/dist/esm/rendering/sprite/Spritesheet.js.map +1 -1
  370. package/dist/esm/rendering/text/DynamicGlyphAtlas.js +3 -9
  371. package/dist/esm/rendering/text/DynamicGlyphAtlas.js.map +1 -1
  372. package/dist/esm/rendering/text/Text.js +9 -9
  373. package/dist/esm/rendering/text/Text.js.map +1 -1
  374. package/dist/esm/rendering/text/TextLayout.d.ts +2 -2
  375. package/dist/esm/rendering/text/TextLayout.js.map +1 -1
  376. package/dist/esm/rendering/text/TextStyle.js.map +1 -1
  377. package/dist/esm/rendering/text/atlas-singleton.js.map +1 -1
  378. package/dist/esm/rendering/texture/DataTexture.d.ts +115 -0
  379. package/dist/esm/rendering/texture/DataTexture.js +173 -0
  380. package/dist/esm/rendering/texture/DataTexture.js.map +1 -0
  381. package/dist/esm/rendering/texture/RenderTexture.d.ts +1 -1
  382. package/dist/esm/rendering/texture/RenderTexture.js +4 -1
  383. package/dist/esm/rendering/texture/RenderTexture.js.map +1 -1
  384. package/dist/esm/rendering/texture/Sampler.js.map +1 -1
  385. package/dist/esm/rendering/texture/Texture.d.ts +2 -2
  386. package/dist/esm/rendering/texture/Texture.js +8 -5
  387. package/dist/esm/rendering/texture/Texture.js.map +1 -1
  388. package/dist/esm/rendering/types.js.map +1 -1
  389. package/dist/esm/rendering/utils.js.map +1 -1
  390. package/dist/esm/rendering/video/Video.d.ts +3 -3
  391. package/dist/esm/rendering/video/Video.js +7 -6
  392. package/dist/esm/rendering/video/Video.js.map +1 -1
  393. package/dist/esm/rendering/webgl2/AbstractWebGl2BatchedRenderer.d.ts +6 -6
  394. package/dist/esm/rendering/webgl2/AbstractWebGl2BatchedRenderer.js +7 -10
  395. package/dist/esm/rendering/webgl2/AbstractWebGl2BatchedRenderer.js.map +1 -1
  396. package/dist/esm/rendering/webgl2/AbstractWebGl2Renderer.d.ts +1 -1
  397. package/dist/esm/rendering/webgl2/AbstractWebGl2Renderer.js +1 -2
  398. package/dist/esm/rendering/webgl2/AbstractWebGl2Renderer.js.map +1 -1
  399. package/dist/esm/rendering/webgl2/WebGl2Backend.d.ts +11 -11
  400. package/dist/esm/rendering/webgl2/WebGl2Backend.js +61 -22
  401. package/dist/esm/rendering/webgl2/WebGl2Backend.js.map +1 -1
  402. package/dist/esm/rendering/webgl2/WebGl2MaskCompositor.d.ts +2 -2
  403. package/dist/esm/rendering/webgl2/WebGl2MaskCompositor.js +6 -8
  404. package/dist/esm/rendering/webgl2/WebGl2MaskCompositor.js.map +1 -1
  405. package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.d.ts +7 -4
  406. package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.js +121 -43
  407. package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.js.map +1 -1
  408. package/dist/esm/rendering/webgl2/WebGl2ParticleRenderer.d.ts +1 -1
  409. package/dist/esm/rendering/webgl2/WebGl2ParticleRenderer.js +10 -18
  410. package/dist/esm/rendering/webgl2/WebGl2ParticleRenderer.js.map +1 -1
  411. package/dist/esm/rendering/webgl2/WebGl2RenderBuffer.d.ts +1 -1
  412. package/dist/esm/rendering/webgl2/WebGl2RenderBuffer.js.map +1 -1
  413. package/dist/esm/rendering/webgl2/WebGl2ShaderBlock.js.map +1 -1
  414. package/dist/esm/rendering/webgl2/WebGl2ShaderMappings.js.map +1 -1
  415. package/dist/esm/rendering/webgl2/WebGl2ShaderProgram.js +54 -22
  416. package/dist/esm/rendering/webgl2/WebGl2ShaderProgram.js.map +1 -1
  417. package/dist/esm/rendering/webgl2/WebGl2SpriteRenderer.d.ts +1 -1
  418. package/dist/esm/rendering/webgl2/WebGl2SpriteRenderer.js +11 -14
  419. package/dist/esm/rendering/webgl2/WebGl2SpriteRenderer.js.map +1 -1
  420. package/dist/esm/rendering/webgl2/WebGl2VertexArrayObject.d.ts +1 -1
  421. package/dist/esm/rendering/webgl2/WebGl2VertexArrayObject.js.map +1 -1
  422. package/dist/esm/rendering/webgpu/AbstractWebGpuRenderer.d.ts +1 -1
  423. package/dist/esm/rendering/webgpu/AbstractWebGpuRenderer.js +1 -2
  424. package/dist/esm/rendering/webgpu/AbstractWebGpuRenderer.js.map +1 -1
  425. package/dist/esm/rendering/webgpu/WebGpuBackend.d.ts +8 -7
  426. package/dist/esm/rendering/webgpu/WebGpuBackend.js +104 -37
  427. package/dist/esm/rendering/webgpu/WebGpuBackend.js.map +1 -1
  428. package/dist/esm/rendering/webgpu/WebGpuBlendState.js.map +1 -1
  429. package/dist/esm/rendering/webgpu/WebGpuMaskCompositor.d.ts +2 -2
  430. package/dist/esm/rendering/webgpu/WebGpuMaskCompositor.js +3 -4
  431. package/dist/esm/rendering/webgpu/WebGpuMaskCompositor.js.map +1 -1
  432. package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.d.ts +15 -2
  433. package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.js +657 -102
  434. package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.js.map +1 -1
  435. package/dist/esm/rendering/webgpu/WebGpuParticleRenderer.d.ts +1 -1
  436. package/dist/esm/rendering/webgpu/WebGpuParticleRenderer.js +100 -56
  437. package/dist/esm/rendering/webgpu/WebGpuParticleRenderer.js.map +1 -1
  438. package/dist/esm/rendering/webgpu/WebGpuSpriteRenderer.d.ts +2 -2
  439. package/dist/esm/rendering/webgpu/WebGpuSpriteRenderer.js +45 -45
  440. package/dist/esm/rendering/webgpu/WebGpuSpriteRenderer.js.map +1 -1
  441. package/dist/esm/rendering/webgpu/compute/WebGpuComputePipeline.d.ts +1 -1
  442. package/dist/esm/rendering/webgpu/compute/index.d.ts +2 -2
  443. package/dist/esm/resources/AbstractAssetFactory.d.ts +1 -1
  444. package/dist/esm/resources/AbstractAssetFactory.js.map +1 -1
  445. package/dist/esm/resources/AssetManifest.d.ts +1 -1
  446. package/dist/esm/resources/AssetManifest.js +2 -2
  447. package/dist/esm/resources/AssetManifest.js.map +1 -1
  448. package/dist/esm/resources/CacheFirstStrategy.d.ts +2 -2
  449. package/dist/esm/resources/CacheFirstStrategy.js.map +1 -1
  450. package/dist/esm/resources/CacheStrategy.d.ts +1 -1
  451. package/dist/esm/resources/FactoryRegistry.d.ts +1 -1
  452. package/dist/esm/resources/FactoryRegistry.js +2 -3
  453. package/dist/esm/resources/FactoryRegistry.js.map +1 -1
  454. package/dist/esm/resources/IndexedDbDatabase.d.ts +1 -1
  455. package/dist/esm/resources/IndexedDbDatabase.js +11 -14
  456. package/dist/esm/resources/IndexedDbDatabase.js.map +1 -1
  457. package/dist/esm/resources/IndexedDbStore.d.ts +1 -1
  458. package/dist/esm/resources/IndexedDbStore.js +2 -7
  459. package/dist/esm/resources/IndexedDbStore.js.map +1 -1
  460. package/dist/esm/resources/Loader.d.ts +9 -9
  461. package/dist/esm/resources/Loader.js +48 -35
  462. package/dist/esm/resources/Loader.js.map +1 -1
  463. package/dist/esm/resources/NetworkOnlyStrategy.d.ts +2 -2
  464. package/dist/esm/resources/NetworkOnlyStrategy.js.map +1 -1
  465. package/dist/esm/resources/factories/BinaryFactory.js.map +1 -1
  466. package/dist/esm/resources/factories/FontFactory.js +1 -1
  467. package/dist/esm/resources/factories/FontFactory.js.map +1 -1
  468. package/dist/esm/resources/factories/ImageFactory.js +4 -4
  469. package/dist/esm/resources/factories/ImageFactory.js.map +1 -1
  470. package/dist/esm/resources/factories/JsonFactory.d.ts +1 -1
  471. package/dist/esm/resources/factories/JsonFactory.js +1 -1
  472. package/dist/esm/resources/factories/JsonFactory.js.map +1 -1
  473. package/dist/esm/resources/factories/MusicFactory.d.ts +1 -1
  474. package/dist/esm/resources/factories/MusicFactory.js +4 -4
  475. package/dist/esm/resources/factories/MusicFactory.js.map +1 -1
  476. package/dist/esm/resources/factories/SoundFactory.d.ts +1 -1
  477. package/dist/esm/resources/factories/SoundFactory.js +3 -3
  478. package/dist/esm/resources/factories/SoundFactory.js.map +1 -1
  479. package/dist/esm/resources/factories/SvgFactory.js +3 -3
  480. package/dist/esm/resources/factories/SvgFactory.js.map +1 -1
  481. package/dist/esm/resources/factories/TextFactory.js +1 -1
  482. package/dist/esm/resources/factories/TextFactory.js.map +1 -1
  483. package/dist/esm/resources/factories/TextureFactory.d.ts +1 -1
  484. package/dist/esm/resources/factories/TextureFactory.js +3 -3
  485. package/dist/esm/resources/factories/TextureFactory.js.map +1 -1
  486. package/dist/esm/resources/factories/VideoFactory.d.ts +2 -2
  487. package/dist/esm/resources/factories/VideoFactory.js +5 -5
  488. package/dist/esm/resources/factories/VideoFactory.js.map +1 -1
  489. package/dist/esm/resources/factories/VttFactory.d.ts +2 -2
  490. package/dist/esm/resources/factories/VttFactory.js +6 -6
  491. package/dist/esm/resources/factories/VttFactory.js.map +1 -1
  492. package/dist/esm/resources/factories/WasmFactory.js.map +1 -1
  493. package/dist/esm/resources/index.d.ts +11 -11
  494. package/dist/esm/resources/utils.js +30 -25
  495. package/dist/esm/resources/utils.js.map +1 -1
  496. package/dist/exo.esm.js +26260 -24256
  497. package/dist/exo.esm.js.map +1 -1
  498. package/package.json +15 -4
package/CHANGELOG.md CHANGED
@@ -4,6 +4,161 @@ All notable changes to ExoJS are documented in this file.
4
4
 
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.8.3] - 2026-05-10
8
+
9
+ ### Engine — Rendering
10
+
11
+ - **`MeshShader` class with dual GLSL + WGSL support.** The 0.8.2
12
+ `MeshShaderConfig` plain interface is replaced by a `MeshShader` class
13
+ accepting `glsl: { vertex, fragment }` and/or `wgsl` source. The WebGPU
14
+ mesh renderer now has a parallel render path for custom-shader meshes
15
+ inside the same render pass, switching pipeline + bind groups between
16
+ batched default draws and per-shader custom draws. New methods
17
+ `getDeclaredUniforms()` and `detectUniformDrift()` parse uniform
18
+ declarations from both languages for CI-style drift checking. **Breaking
19
+ change against the 0.8.2 plain-interface shape; clean break, no
20
+ backwards-compat shim — the 0.8.x series is pre-1.0.**
21
+
22
+ - **`DataTexture` for CPU-uploaded GPU textures.** New primitive whose
23
+ pixels live in a CPU-side typed array. Mutate the `buffer` directly and
24
+ call `commit()` to upload the whole array, or `commitRect(x, y, w, h)`
25
+ for partial uploads (cheaper for ring-buffer patterns like
26
+ spectrograms). Formats: `r8` / `r32f` / `rgba8` / `rgba32f`; TypeScript
27
+ narrows the buffer typed-array kind from the format. Bring-your-own
28
+ buffer via `options.data` (`Uint8Array | Float32Array | ArrayBuffer`)
29
+ for SharedArrayBuffer / Worker / pool scenarios. Extends `Texture` so
30
+ it's accepted everywhere a `Texture` is.
31
+
32
+ ### Engine — Audio
33
+
34
+ - **`BeatDetector` visual getters for per-frame polling.** New derived
35
+ getters `pulse`, `barPulse`, `justBeat`, `secondsSinceLastBeat` and
36
+ method `subdivisionPhase(division)`. All pure derivations from existing
37
+ state — no new event-handling glue required for typical "pulse on the
38
+ beat" / "trigger on every 16th note" visuals. Mutable fields
39
+ `pulseHalfLife` (default 0.15s), `barPulseHalfLife` (0.3s), and
40
+ `justBeatWindow` (0.03s) tune the envelopes.
41
+
42
+ - **`AudioAnalyser` mel and log spectrum mapping.** New methods
43
+ `getSpectrumMel` / `getSpectrumMelFloat` / `getSpectrumLog` /
44
+ `getSpectrumLogFloat` produce perceptually-weighted or octave-uniform
45
+ band sequences from the linear FFT bins. Filterbanks are built from
46
+ the previously-orphaned `dsp/mel.ts` utilities and cached per
47
+ `(bands, fMin, fMax)` combination — rebuild only on parameter change.
48
+ Default 32 bands, 20 Hz to 20 kHz (clamped to nyquist).
49
+
50
+ - **`source` as constructor option for `AudioAnalyser` and `BeatDetector`.**
51
+ Additive ergonomic for one-shot construction:
52
+ `new AudioAnalyser({ source: music, fftSize: 1024 })`. The setter
53
+ remains usable for runtime source switches.
54
+
55
+ ### Engine — Debug
56
+
57
+ - **`RenderPassInspectorLayer`.** New debug layer (in the
58
+ `@codexo/exojs/debug` subpath) that lists every `RenderNode` with an
59
+ active filter chain each frame, showing total pass count, per-drawable
60
+ filter sequence, bounding-box dimensions, and mask/cache flags. For
61
+ deep per-pass inspection (intermediate render-target contents, shader
62
+ source, uniform values), use Spector.js or Chrome DevTools' WebGPU
63
+ panel — the engine now emits debug-group labels around filter and
64
+ mesh-custom-shader passes (`WebGpuShaderFilter pass`,
65
+ `MeshShader (custom)`, `WebGpuMaskCompositor pass`) so external capture
66
+ tools display meaningful pass names.
67
+
68
+ ### Site / Docs
69
+
70
+ - New guide chapter stubs: `6.4 Custom mesh shaders`,
71
+ `5.5 Audio-reactive visualization`, `7.6 Render pipeline debugging`.
72
+ - API doc auto-regenerated for `MeshShader` and `DataTexture`.
73
+
74
+ ### Verification
75
+
76
+ - Engine: 103/103 suites, 1338/1338 tests, lint:strict 0/0, typecheck clean.
77
+ - Site: build green (494 pages), check-ts 0/0.
78
+
79
+ ## [0.8.2] - 2026-05-09
80
+
81
+ ### Engine
82
+
83
+ - **`Mesh` accepts custom WebGL2 shaders.** New `MeshShaderConfig` + `MeshShaderUniformValue`
84
+ exports. Supply `shader: { vertexSource, fragmentSource, uniforms }` in `MeshOptions` to
85
+ bind a custom GLSL ES 3.00 program against the standard mesh vertex layout. Auto-bound
86
+ uniforms (`u_projection`, `u_translation`, `u_tint`, `u_texture`) are set only when the
87
+ shader declares them, so Shadertoy-style fullscreen passes can ignore them entirely.
88
+ Texture uniforms claim slots 1–7. WebGL2 only in this release; the WebGPU mesh
89
+ renderer throws a clear error pointing to the WebGL2 backend if `mesh.shader` is set.
90
+
91
+ - **Filter chain memory: ping-pong RT reuse.** `RenderNode._renderContentToTexture` now
92
+ releases the previous step's RenderTexture immediately after each `filter.apply`, so
93
+ the pool can hand the same memory back to the next step. Multi-filter chains drop from
94
+ N+1 simultaneously-allocated RTs to a steady-state of 2. ~60% RT-memory reduction on
95
+ 4-filter 1080p chains. Behaviour-identical; no public API change.
96
+
97
+ ### Site / Docs
98
+
99
+ - Part 2 "Core Concepts" guide section published (6 chapters, source-verified):
100
+ Application, Scenes, Scene lifecycle, Scene graph, Coordinates and views,
101
+ Loading and resources.
102
+ - Astro `6.3.0 → 6.3.1`, `@types/node 25.6.0 → 25.6.2` in site/.
103
+
104
+ ### Verification
105
+
106
+ - Engine: 100/100 suites, 1266/1266 tests, lint:strict 0/0, typecheck clean.
107
+ - Site: build green (488 pages), check-ts 0/0, screenshot smoke 36/36.
108
+
109
+ ## [0.8.1] - 2026-05-08
110
+
111
+ Three small additive features that close the remaining examples-driven API gaps from
112
+ the 0.8.0 audit, plus a long-overdue lint/format tooling consolidation and a 19-chapter
113
+ examples reorganisation.
114
+
115
+ ### Added
116
+
117
+ - **`Sound` spatial falloff configuration.** `DistanceModel` type (`'linear' | 'inverse'
118
+ | 'exponential'`), plus optional `distanceModel`, `refDistance`, `maxDistance`, and
119
+ `rolloffFactor` fields on `SoundOptions`. The four are also exposed as live property
120
+ setters that lazy-forward to the attached `PannerNode`. New public `Sound.audioBuffer`
121
+ getter to share one decoded buffer across multiple `Sound` instances.
122
+ - **`LutFilter`** — new colour-pipeline primitive that maps every pixel through a
123
+ Look-Up Table texture. Supports both 1D LUTs (`N×1`, indexed by red channel — palette
124
+ cycling, indexed-colour effects) and 3D LUTs (`N²×N` unwrapped cube with trilinear
125
+ slice interpolation — cinematic colour grading, tone mapping, film stock emulation,
126
+ accessibility filters). Backend selection is automatic. Static helpers
127
+ `LutFilter.identityLut1D(size)`, `LutFilter.identityLut3D(size)`,
128
+ `LutFilter.fromImage(image)` cover the standard DaVinci/OBS/Photoshop LUT-export
129
+ workflows.
130
+ - **`CompressorFilter.reduction`** — public getter forwarding the live gain reduction
131
+ in dB from the underlying `DynamicsCompressorNode`. Use as a meter source for
132
+ visualisations or sidechain triggers.
133
+
134
+ ### Examples
135
+
136
+ - Migrated `examples/public/examples/` to a 19-chapter pedagogical structure: getting
137
+ started, application & scenes, sprites & textures, tweens & animation, input, scene
138
+ graph, audio basics, spatial audio, filters, particles, text & fonts, geometry &
139
+ graphics, render targets, performance, audio FX, beat detection, debug layer, custom
140
+ renderers, showcase. Old chapter directories (`collision-detection`, `extras`,
141
+ `particle-system`, `rendering`, `webgpu`) removed.
142
+ - New examples: `spatial-audio/falloff-curves.js`, `filters/palette-cycling.js`,
143
+ `showcase/color-grading.js`. The compressor demo gained a live gain-reduction meter.
144
+
145
+ ### Tooling
146
+
147
+ - ESLint config consolidated into a single `eslint.config.ts` driven by ESLint 10 +
148
+ `typescript-eslint`'s type-aware checks plus `simple-import-sort`,
149
+ `unused-imports`, `unicorn`, and `security` plugins. `lint:strict` is the
150
+ release-gate variant, scoped to `src/**/*.ts` and run with `--max-warnings=0` (warnings
151
+ fail the build); `lint` is the broader development view across `src`, `test`, and
152
+ examples. Per-subsystem override blocks are documented as known deviations to tighten
153
+ over time.
154
+ - Tightened to error: `eqeqeq`, `no-floating-promises`, `no-base-to-string`,
155
+ `only-throw-error`, `switch-exhaustiveness-check`, `no-non-null-assertion`,
156
+ `complexity` (cap 20). Added: `no-self-compare`, `no-unreachable-loop`,
157
+ `default-case-last`, `prefer-promise-reject-errors`, `no-promise-executor-return`,
158
+ `no-unmodified-loop-condition`, plus six TypeScript and six Unicorn correctness rules.
159
+ - Prettier `printWidth: 160`, `.editorconfig` matched. Engine code reformatted to
160
+ 2-space indent.
161
+
7
162
  ## [0.8.0] - 2026-05-07
8
163
 
9
164
  Wholesale rewrite of the particle subsystem around a data-oriented core
@@ -33,19 +188,19 @@ automatic and per-system; user code is unchanged across both paths.
33
188
  `Uint32Array` / `Uint16Array` channels addressed by slot index:
34
189
 
35
190
  ```ts
36
- system.posX[slot]
37
- system.posY[slot]
38
- system.velX[slot]
39
- system.velY[slot]
40
- system.scaleX[slot]
41
- system.scaleY[slot]
42
- system.rotations[slot]
43
- system.rotationSpeeds[slot]
44
- system.color[slot] // packed 0xAABBGGRR
45
- system.elapsed[slot]
46
- system.lifetime[slot]
47
- system.textureIndex[slot]
48
- system.liveCount // [0, liveCount) is the live range
191
+ system.posX[slot];
192
+ system.posY[slot];
193
+ system.velX[slot];
194
+ system.velY[slot];
195
+ system.scaleX[slot];
196
+ system.scaleY[slot];
197
+ system.rotations[slot];
198
+ system.rotationSpeeds[slot];
199
+ system.color[slot]; // packed 0xAABBGGRR
200
+ system.elapsed[slot];
201
+ system.lifetime[slot];
202
+ system.textureIndex[slot];
203
+ system.liveCount; // [0, liveCount) is the live range
49
204
  ```
50
205
 
51
206
  Capacity is fixed at construction (default 4096) — no reallocations.
@@ -57,17 +212,17 @@ instead of the previous O(n²) splice loop with scattered expirations).
57
212
 
58
213
  Spawn-time random sampling and lifetime-parameterised evaluation:
59
214
 
60
- | Type | Use |
61
- |---|---|
62
- | `Constant<T>` | Always-same value |
63
- | `Range` | Uniform random number in `[min, max]` |
64
- | `VectorRange` | Per-axis random vector |
65
- | `ConeDirection` | Random unit vector in a cone × speed range |
66
- | `CircleArea` | Random point in/on a circle |
67
- | `BoxArea` | Random point in/on an AABB |
68
- | `LineSegment` | Random point on a segment |
69
- | `Curve` | Piecewise-linear keyframe scalar by lifetime ratio |
70
- | `Gradient` | Piecewise-linear keyframe color, with `evaluateRgba()` for direct u32 packing |
215
+ | Type | Use |
216
+ | --------------- | ----------------------------------------------------------------------------- |
217
+ | `Constant<T>` | Always-same value |
218
+ | `Range` | Uniform random number in `[min, max]` |
219
+ | `VectorRange` | Per-axis random vector |
220
+ | `ConeDirection` | Random unit vector in a cone × speed range |
221
+ | `CircleArea` | Random point in/on a circle |
222
+ | `BoxArea` | Random point in/on an AABB |
223
+ | `LineSegment` | Random point on a segment |
224
+ | `Curve` | Piecewise-linear keyframe scalar by lifetime ratio |
225
+ | `Gradient` | Piecewise-linear keyframe color, with `evaluateRgba()` for direct u32 packing |
71
226
 
72
227
  `Curve` and `Gradient` cache the last segment so monotonically
73
228
  advancing `t` (the typical case for per-particle lifetime sampling)
@@ -79,9 +234,15 @@ Three module bases. Each registered on a system via the corresponding
79
234
  `addX` method; each runs in its declared phase per-frame.
80
235
 
81
236
  ```ts
82
- abstract class SpawnModule { apply(system, dt: number): void; }
83
- abstract class UpdateModule { apply(system, dt: number): void; }
84
- abstract class DeathModule { onDeath(system, slot: number): void; }
237
+ abstract class SpawnModule {
238
+ apply(system, dt: number): void;
239
+ }
240
+ abstract class UpdateModule {
241
+ apply(system, dt: number): void;
242
+ }
243
+ abstract class DeathModule {
244
+ onDeath(system, slot: number): void;
245
+ }
85
246
  ```
86
247
 
87
248
  **Built-in spawn modules:**
@@ -121,7 +282,7 @@ for one `ParticleSystem`. At construction time it:
121
282
 
122
283
  1. Walks the registered update modules, collecting each module's
123
284
  `WgslContribution` (uniform field declarations + texture bindings
124
- + WGSL body snippet).
285
+ - WGSL body snippet).
125
286
  2. Generates a composite WGSL compute shader: SoA storage bindings +
126
287
  sim/module uniform structs + module texture bindings + a `main`
127
288
  function containing integration → all module bodies in registration
@@ -151,8 +312,8 @@ Opt-in is a single constructor option — no imperative toggle:
151
312
 
152
313
  ```ts
153
314
  const system = new ParticleSystem(texture, {
154
- capacity: 8192,
155
- backend: app.backend, // CPU-routed on WebGL2, GPU-routed on WebGPU
315
+ capacity: 8192,
316
+ backend: app.backend, // CPU-routed on WebGL2, GPU-routed on WebGPU
156
317
  });
157
318
  ```
158
319
 
@@ -165,25 +326,25 @@ modules after that throws.
165
326
 
166
327
  The following symbols are deleted. Migration recipes follow the table.
167
328
 
168
- | Removed | Replacement |
169
- |---|---|
170
- | `Particle` (class) | SoA arrays on `ParticleSystem` (`system.posX[slot]`, etc.) |
171
- | `ParticleProperties` (interface) | None — slot-indexed arrays replace the per-particle object |
172
- | `ParticleEmitter` (interface) | `SpawnModule` (abstract class) |
173
- | `ParticleOptions` | Per-property `Distribution<T>` in the spawn module's config |
174
- | `UniversalEmitter` | `RateSpawn` |
175
- | `ParticleAffector` (interface) | `UpdateModule` (abstract class) |
176
- | `ColorAffector` | `ColorOverLifetime` + `Gradient` |
177
- | `ForceAffector` | `ApplyForce` |
178
- | `ScaleAffector` | `ScaleOverLifetime` + `Curve` |
179
- | `TorqueAffector` | `RotateOverLifetime` |
180
- | `system.requestParticle()` | `system.spawn(): number` (slot index, or `-1` at capacity) |
181
- | `system.emitParticle(p)` | (gone — `spawn()` already commits the slot to the live range) |
182
- | `system.updateParticle(p, dt)` | (gone — internal to `update()`) |
183
- | `system.addEmitter(e)` | `system.addSpawnModule(m)` |
184
- | `system.addAffector(a)` | `system.addUpdateModule(m)` |
185
- | `system.particles` (`Array<Particle>`) | `system.posX` / `system.posY` / ... `system.liveCount` |
186
- | `system.graveyard` | (gone — no graveyard; slots are recycled in place) |
329
+ | Removed | Replacement |
330
+ | -------------------------------------- | ------------------------------------------------------------- |
331
+ | `Particle` (class) | SoA arrays on `ParticleSystem` (`system.posX[slot]`, etc.) |
332
+ | `ParticleProperties` (interface) | None — slot-indexed arrays replace the per-particle object |
333
+ | `ParticleEmitter` (interface) | `SpawnModule` (abstract class) |
334
+ | `ParticleOptions` | Per-property `Distribution<T>` in the spawn module's config |
335
+ | `UniversalEmitter` | `RateSpawn` |
336
+ | `ParticleAffector` (interface) | `UpdateModule` (abstract class) |
337
+ | `ColorAffector` | `ColorOverLifetime` + `Gradient` |
338
+ | `ForceAffector` | `ApplyForce` |
339
+ | `ScaleAffector` | `ScaleOverLifetime` + `Curve` |
340
+ | `TorqueAffector` | `RotateOverLifetime` |
341
+ | `system.requestParticle()` | `system.spawn(): number` (slot index, or `-1` at capacity) |
342
+ | `system.emitParticle(p)` | (gone — `spawn()` already commits the slot to the live range) |
343
+ | `system.updateParticle(p, dt)` | (gone — internal to `update()`) |
344
+ | `system.addEmitter(e)` | `system.addSpawnModule(m)` |
345
+ | `system.addAffector(a)` | `system.addUpdateModule(m)` |
346
+ | `system.particles` (`Array<Particle>`) | `system.posX` / `system.posY` / ... `system.liveCount` |
347
+ | `system.graveyard` | (gone — no graveyard; slots are recycled in place) |
187
348
 
188
349
  ### Migration
189
350
 
@@ -203,16 +364,22 @@ options.velocity.set(/* ... */);
203
364
 
204
365
  // After — bonfire
205
366
  const system = new ParticleSystem(texture);
206
- system.addSpawnModule(new RateSpawn({
367
+ system.addSpawnModule(
368
+ new RateSpawn({
207
369
  rate: new Constant(50),
208
370
  lifetime: new Range(5, 10),
209
371
  position: new VectorRange(-50, 50, -10, 10),
210
372
  velocity: new ConeDirection(-Math.PI / 2, Math.PI / 36, 60, 80),
211
- }));
212
- system.addUpdateModule(new ColorOverLifetime(new Gradient([
213
- { t: 0, color: new Color(194, 64, 30, 1) },
214
- { t: 1, color: new Color(0, 0, 0, 0) },
215
- ])));
373
+ }),
374
+ );
375
+ system.addUpdateModule(
376
+ new ColorOverLifetime(
377
+ new Gradient([
378
+ { t: 0, color: new Color(194, 64, 30, 1) },
379
+ { t: 1, color: new Color(0, 0, 0, 0) },
380
+ ]),
381
+ ),
382
+ );
216
383
  // no per-frame mutation needed.
217
384
  ```
218
385
 
@@ -228,23 +395,23 @@ system.addUpdateModule(new ApplyForce(0, 980));
228
395
  ```ts
229
396
  // Before — custom affector
230
397
  class AlphaFade {
231
- apply(particle, delta) {
232
- particle.tint.a = particle.remainingRatio;
233
- return this;
234
- }
235
- destroy() {}
398
+ apply(particle, delta) {
399
+ particle.tint.a = particle.remainingRatio;
400
+ return this;
401
+ }
402
+ destroy() {}
236
403
  }
237
404
 
238
405
  // After
239
406
  class AlphaFadeOverLifetime extends UpdateModule {
240
- apply(system) {
241
- const { color, elapsed, lifetime, liveCount } = system;
242
- for (let i = 0; i < liveCount; i++) {
243
- const remaining = 1 - elapsed[i] / lifetime[i];
244
- const a = (Math.max(0, Math.min(1, remaining)) * 255) & 255;
245
- color[i] = (color[i] & 0x00ffffff) | (a << 24);
246
- }
407
+ apply(system) {
408
+ const { color, elapsed, lifetime, liveCount } = system;
409
+ for (let i = 0; i < liveCount; i++) {
410
+ const remaining = 1 - elapsed[i] / lifetime[i];
411
+ const a = (Math.max(0, Math.min(1, remaining)) * 255) & 255;
412
+ color[i] = (color[i] & 0x00ffffff) | (a << 24);
247
413
  }
414
+ }
248
415
  }
249
416
  ```
250
417
 
@@ -279,12 +446,12 @@ new ParticleSystem(texture);
279
446
  new ParticleSystem(texture, 4096);
280
447
 
281
448
  // 0.8.0:
282
- new ParticleSystem(); // untextured (1×1 white), CPU/GPU auto-routed
283
- new ParticleSystem(spark); // simple textured particles
284
- new ParticleSystem(spark, { capacity: 8192 }); // explicit capacity
285
- new ParticleSystem(atlas, [r0, r1, r2]); // multi-frame atlas
449
+ new ParticleSystem(); // untextured (1×1 white), CPU/GPU auto-routed
450
+ new ParticleSystem(spark); // simple textured particles
451
+ new ParticleSystem(spark, { capacity: 8192 }); // explicit capacity
452
+ new ParticleSystem(atlas, [r0, r1, r2]); // multi-frame atlas
286
453
  new ParticleSystem(atlas, frames, { capacity: 8192 }); // atlas + capacity
287
- new ParticleSystem(sheet); // spritesheet shorthand
454
+ new ParticleSystem(sheet); // spritesheet shorthand
288
455
  new ParticleSystem(sheet, { capacity: 4096 });
289
456
  ```
290
457
 
@@ -300,9 +467,9 @@ constructor(spritesheet: Spritesheet, options?: ParticleSystemOptions);
300
467
  Compile-time errors for illegal combinations:
301
468
 
302
469
  ```ts
303
- new ParticleSystem(spark, sheet); // ✗ no overload matches
304
- new ParticleSystem(sheet, frames); // ✗ frames only valid with Texture
305
- new ParticleSystem({ frames }); // ✗ frames isn't an option
470
+ new ParticleSystem(spark, sheet); // ✗ no overload matches
471
+ new ParticleSystem(sheet, frames); // ✗ frames only valid with Texture
472
+ new ParticleSystem({ frames }); // ✗ frames isn't an option
306
473
  ```
307
474
 
308
475
  **No `backend` option** — the renderer auto-discovers the active backend
@@ -326,19 +493,21 @@ frame chooser:
326
493
 
327
494
  ```ts
328
495
  const system = new ParticleSystem({
329
- texture: explosionAtlas,
330
- frames: [
331
- new Rectangle(0, 0, 32, 32), // index 0 — flame core
332
- new Rectangle(32, 0, 32, 32), // index 1 — smoke ring
333
- new Rectangle(64, 0, 32, 32), // index 2 — ember
334
- ],
496
+ texture: explosionAtlas,
497
+ frames: [
498
+ new Rectangle(0, 0, 32, 32), // index 0 — flame core
499
+ new Rectangle(32, 0, 32, 32), // index 1 — smoke ring
500
+ new Rectangle(64, 0, 32, 32), // index 2 — ember
501
+ ],
335
502
  });
336
503
 
337
- system.addSpawnModule(new BurstSpawn({
504
+ system.addSpawnModule(
505
+ new BurstSpawn({
338
506
  schedule: [{ time: 0, count: 60 }],
339
507
  velocity: ConeDirection.omni(120, 280),
340
- textureIndex: new Range(0, 2), // each spawn picks a random frame
341
- }));
508
+ textureIndex: new Range(0, 2), // each spawn picks a random frame
509
+ }),
510
+ );
342
511
  ```
343
512
 
344
513
  `Spritesheet` integration via `spritesheet: sheet` extracts texture +
@@ -373,6 +542,7 @@ update). `spawn()` always returns the next sequential slot.
373
542
 
374
543
  In GPU mode, no compaction happens — readback would be required to
375
544
  move slots whose authoritative position lives in GPU memory. Instead:
545
+
376
546
  - Each particle has an `alive: Uint8Array` flag (1 = alive, 0 = dead).
377
547
  - `spawn()` finds the first dead slot via a round-robin hint pointer
378
548
  (amortised O(1), worst case O(capacity)).
@@ -422,7 +592,7 @@ signed stick channels, and Joy-Con-honest mappings.
422
592
  ```ts
423
593
  // Per inputManager (manual unbind):
424
594
  app.input.onTrigger(GamepadButton.South, () => player.jump());
425
- app.input.onActive(GamepadAxis.LeftStickX, (v) => player.x += v * 5);
595
+ app.input.onActive(GamepadAxis.LeftStickX, v => (player.x += v * 5));
426
596
  app.input.onStart([Keyboard.Space, GamepadButton.South], () => fire());
427
597
 
428
598
  // Per gamepad (slot-aware, listener survives disconnect/reconnect):
@@ -466,8 +636,8 @@ default `'sticky'` (each pad keeps its slot through disconnects).
466
636
  disconnect (good for hot-seat couch coop where "the first N pads are
467
637
  the N players" is the desired semantic).
468
638
 
469
- In compact mode, the disconnect signal fires on the slot that *ended
470
- up* empty after the shift (not the slot the disconnected hardware
639
+ In compact mode, the disconnect signal fires on the slot that _ended
640
+ up_ empty after the shift (not the slot the disconnected hardware
471
641
  originally occupied), keeping `pad.connected === false` consistent with
472
642
  the fired event. Slots that received a different physical pad through
473
643
  the shift dispatch a separate signal:
@@ -481,6 +651,7 @@ player when slots renumber.
481
651
  ### Added — Generic signals
482
652
 
483
653
  Per-pad:
654
+
484
655
  - `pad.onConnect: Signal<[]>`
485
656
  - `pad.onDisconnect: Signal<[]>`
486
657
  - `pad.onButtonDown: Signal<[GamepadButton, number]>`
@@ -488,6 +659,7 @@ Per-pad:
488
659
  - `pad.onAxisChange: Signal<[GamepadAxis, number]>`
489
660
 
490
661
  Aggregate across all pads:
662
+
491
663
  - `inputManager.onAnyGamepadButtonDown: Signal<[Gamepad, GamepadButton, number]>`
492
664
  - `inputManager.onAnyGamepadButtonUp: Signal<[Gamepad, GamepadButton, number]>`
493
665
  - `inputManager.onAnyGamepadAxisChange: Signal<[Gamepad, GamepadAxis, number]>`
@@ -496,7 +668,7 @@ Aggregate across all pads:
496
668
 
497
669
  ```ts
498
670
  if (pad.canVibrate) {
499
- await pad.vibrate({ duration: 200, weakMagnitude: 0.5, strongMagnitude: 1.0 });
671
+ await pad.vibrate({ duration: 200, weakMagnitude: 0.5, strongMagnitude: 1.0 });
500
672
  }
501
673
  pad.stopVibration();
502
674
  ```
@@ -517,18 +689,18 @@ remain available for buttons-style 0..1 input.
517
689
 
518
690
  ```ts
519
691
  // Stick-style — one binding per axis, signed value:
520
- this.inputs.onActive(GamepadAxis.LeftStickX, (x) => player.x += x * 5);
692
+ this.inputs.onActive(GamepadAxis.LeftStickX, x => (player.x += x * 5));
521
693
 
522
694
  // Buttons-style — separate bindings per direction, 0..1 each:
523
- this.inputs.onActive(GamepadAxis.LeftStickLeft, (v) => player.x -= v * 5);
524
- this.inputs.onActive(GamepadAxis.LeftStickRight, (v) => player.x += v * 5);
695
+ this.inputs.onActive(GamepadAxis.LeftStickLeft, v => (player.x -= v * 5));
696
+ this.inputs.onActive(GamepadAxis.LeftStickRight, v => (player.x += v * 5));
525
697
  ```
526
698
 
527
699
  ### Added — `pad.hasChannel(channel)` capability check
528
700
 
529
701
  ```ts
530
702
  if (pad.hasChannel(GamepadAxis.RightStickX)) {
531
- pad.onActive(GamepadAxis.RightStickX, (v) => crosshair.x += v * 8);
703
+ pad.onActive(GamepadAxis.RightStickX, v => (crosshair.x += v * 8));
532
704
  }
533
705
  ```
534
706
 
@@ -545,19 +717,19 @@ Internally tracks each binding and calls `.unbind()` in `Scene.destroy`.
545
717
  ### Added — Steam Deck / Steam Virtual Gamepad / Valve fallback
546
718
 
547
719
  New `SteamDeckGamepadMapping` covers the raw HID layout reported by the
548
- Steam Deck (and likely future Valve hardware) when Steam Input is *not*
720
+ Steam Deck (and likely future Valve hardware) when Steam Input is _not_
549
721
  intercepting the device. Indices follow the SDL_GameControllerDB Linux
550
722
  entry: face buttons at 3-6, D-pad at 16-19, paddles at 20-23, triggers
551
723
  as analog axes 8/9.
552
724
 
553
725
  Routing rules added to `builtInGamepadDefinitions`:
554
726
 
555
- | Browser ID | Mapping |
556
- |---|---|
557
- | `28de:1102`, `28de:1142` | `SteamControllerGamepadMapping` (existing, original Steam Controller raw) |
558
- | `28de:11ff` (Steam Virtual Gamepad — any controller via Steam Input) | `GenericDualAnalogGamepadMapping` (W3C standard Xbox emulation) |
559
- | `28de:1205` | `SteamDeckGamepadMapping` (raw Steam Deck) |
560
- | Vendor `28de` (anything else from Valve, e.g. future Steam Controller 2 raw) | `SteamDeckGamepadMapping` (best-effort fallback) |
727
+ | Browser ID | Mapping |
728
+ | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
729
+ | `28de:1102`, `28de:1142` | `SteamControllerGamepadMapping` (existing, original Steam Controller raw) |
730
+ | `28de:11ff` (Steam Virtual Gamepad — any controller via Steam Input) | `GenericDualAnalogGamepadMapping` (W3C standard Xbox emulation) |
731
+ | `28de:1205` | `SteamDeckGamepadMapping` (raw Steam Deck) |
732
+ | Vendor `28de` (anything else from Valve, e.g. future Steam Controller 2 raw) | `SteamDeckGamepadMapping` (best-effort fallback) |
561
733
 
562
734
  Enum: `GamepadMappingFamily.SteamDeck` added.
563
735
 
@@ -610,7 +782,7 @@ app.input.getGamepad(0);
610
782
  ### Fixed — Compact-mode disconnect ordering
611
783
 
612
784
  In `'compact'` slot strategy, `onDisconnect` previously fired on the
613
- slot the disconnected hardware originally occupied — *before* the
785
+ slot the disconnected hardware originally occupied — _before_ the
614
786
  compaction shift moved a different physical pad into that slot. User
615
787
  code observing the event would see `pad.connected === true` because
616
788
  the slot had been silently re-bound by the shift. Now compaction is
@@ -622,13 +794,13 @@ ended up empty (the trailing slot). Sticky behaviour is unchanged.
622
794
  The unified `GamepadChannel` enum is split into two disjoint enums for
623
795
  nominal type safety:
624
796
 
625
- | Old | New (user-facing) | New (internal type) |
626
- |---|---|---|
627
- | `GamepadChannel.ButtonSouth` | `GamepadButton.South` | `GamepadButtonChannel.South` |
628
- | `GamepadChannel.ButtonEast` | `GamepadButton.East` | `GamepadButtonChannel.East` |
629
- | `GamepadChannel.LeftShoulder` | `GamepadButton.LeftShoulder` | `GamepadButtonChannel.LeftShoulder` |
630
- | `GamepadChannel.LeftStickLeft` | `GamepadAxis.LeftStickLeft` | `GamepadAxisChannel.LeftStickLeft` |
631
- | ... | ... | ... |
797
+ | Old | New (user-facing) | New (internal type) |
798
+ | ------------------------------ | ---------------------------- | ----------------------------------- |
799
+ | `GamepadChannel.ButtonSouth` | `GamepadButton.South` | `GamepadButtonChannel.South` |
800
+ | `GamepadChannel.ButtonEast` | `GamepadButton.East` | `GamepadButtonChannel.East` |
801
+ | `GamepadChannel.LeftShoulder` | `GamepadButton.LeftShoulder` | `GamepadButtonChannel.LeftShoulder` |
802
+ | `GamepadChannel.LeftStickLeft` | `GamepadAxis.LeftStickLeft` | `GamepadAxisChannel.LeftStickLeft` |
803
+ | ... | ... | ... |
632
804
 
633
805
  User code references the namespace mirrors (`GamepadButton.X`,
634
806
  `GamepadAxis.Y`) — same `Pointer.X` / `Keyboard.Space` convention. Type
@@ -670,11 +842,11 @@ instead of firing every frame.
670
842
 
671
843
  ```ts
672
844
  // Before:
673
- new Gamepad(index, channels, mapping)
674
- new Gamepad(browserGamepad, channels, definition)
845
+ new Gamepad(index, channels, mapping);
846
+ new Gamepad(browserGamepad, channels, definition);
675
847
 
676
848
  // After (engine-internal — InputManager handles slot allocation):
677
- new Gamepad(slot, channels)
849
+ new Gamepad(slot, channels);
678
850
  // followed by pad._bind(browserGamepad, definition) on connect
679
851
  ```
680
852
 
@@ -696,7 +868,7 @@ import { GamepadButton, Keyboard } from '@codexo/exojs';
696
868
 
697
869
  // Manual lifecycle
698
870
  const binding = app.input.onTrigger(GamepadButton.South, () => player.jump());
699
- binding.unbind(); // when done
871
+ binding.unbind(); // when done
700
872
 
701
873
  // Auto-disposed on scene unload
702
874
  this.inputs.onTrigger(GamepadButton.South, () => player.jump());
@@ -707,37 +879,31 @@ this.app.input.gamepads[0].onTrigger(GamepadButton.South, () => player.jump());
707
879
 
708
880
  ```ts
709
881
  // Stick movement — before:
710
- const moveLeft = new Input(GamepadChannel.LeftStickLeft);
882
+ const moveLeft = new Input(GamepadChannel.LeftStickLeft);
711
883
  const moveRight = new Input(GamepadChannel.LeftStickRight);
712
884
  app.input.add(moveLeft);
713
885
  app.input.add(moveRight);
714
886
  // per frame: const x = moveRight.value - moveLeft.value;
715
887
 
716
888
  // After (signed aggregate channel):
717
- this.inputs.onActive(GamepadAxis.LeftStickX, (x) => player.x += x * 5);
889
+ this.inputs.onActive(GamepadAxis.LeftStickX, x => (player.x += x * 5));
718
890
  ```
719
891
 
720
892
  ```ts
721
893
  // Custom mapping — before:
722
894
  import { GamepadMapping, GamepadChannel } from '@codexo/exojs';
723
895
  const buttons = GamepadMapping.createControls([
724
- [0, GamepadChannel.ButtonSouth],
725
- [1, GamepadChannel.ButtonEast],
896
+ [0, GamepadChannel.ButtonSouth],
897
+ [1, GamepadChannel.ButtonEast],
726
898
  ]);
727
899
 
728
900
  // After:
729
901
  import { GamepadButton, GamepadMapping, GamepadMappingFamily } from '@codexo/exojs';
730
902
  class MyMapping extends GamepadMapping {
731
- public readonly family = GamepadMappingFamily.GenericDualAnalog;
732
- public constructor() {
733
- super(
734
- [
735
- new GamepadButton(0, GamepadButton.South),
736
- new GamepadButton(1, GamepadButton.East),
737
- ],
738
- [],
739
- );
740
- }
903
+ public readonly family = GamepadMappingFamily.GenericDualAnalog;
904
+ public constructor() {
905
+ super([new GamepadButton(0, GamepadButton.South), new GamepadButton(1, GamepadButton.East)], []);
906
+ }
741
907
  }
742
908
  ```
743
909
 
@@ -863,7 +1029,7 @@ indexing is now automatic and persistent).
863
1029
  audio, collision, scene-graph, interaction. Each domain has its own
864
1030
  script (`npm run perf:bench:rendering`, `:audio`, `:collision`,
865
1031
  `:scene-graph`, `:interaction`) plus `:all` aggregator. Output: JSON
866
- + Markdown to `test/perf/results/`.
1032
+ - Markdown to `test/perf/results/`.
867
1033
  - **Baseline snapshot** committed as `test/perf/results/baseline.md` —
868
1034
  reference numbers at 0.7.10 for future regression detection.
869
1035
  - **Auto-profiler** (`npm run perf:profile`, `:gc` variant with
@@ -903,6 +1069,7 @@ also makes the `useSpatialIndex` opt-in flag unnecessary and **the
903
1069
  flag has been removed entirely**.
904
1070
 
905
1071
  **How it works now:**
1072
+
906
1073
  - A persistent quadtree is created lazily when the first interactive
907
1074
  node enters the scene.
908
1075
  - `Container.addChild` / `removeChild` walk subtrees and add/remove
@@ -943,7 +1110,7 @@ actually-moved nodes.
943
1110
 
944
1111
  ```ts
945
1112
  // Before:
946
- app.interaction.useSpatialIndex = true; // flag opt-in
1113
+ app.interaction.useSpatialIndex = true; // flag opt-in
947
1114
 
948
1115
  // After:
949
1116
  // Nothing — index is automatic. Just have at least one interactive
@@ -1046,7 +1213,7 @@ Fixes a GLSL compile-error in the 0.7.8 shader auto-upgrade path.
1046
1213
  ### Fixed
1047
1214
 
1048
1215
  - **`upgradeFragmentShaderToGl300()` now always prepends `precision highp
1049
- float;`** before the `out vec4 fragColor;` declaration. Previously, if
1216
+ float;`** before the `out vec4 fragColor;` declaration. Previously, if
1050
1217
  the user's source already contained a precision declaration anywhere
1051
1218
  (e.g., `precision lowp float;` mid-source), the upgrader skipped its
1052
1219
  own injection — but the user's declaration came AFTER the
@@ -1057,7 +1224,7 @@ Fixes a GLSL compile-error in the 0.7.8 shader auto-upgrade path.
1057
1224
 
1058
1225
  Multiple precision declarations are legal in GLSL ES 3.00 with
1059
1226
  last-precision-wins semantics. The fix always injects `precision highp
1060
- float;` at line 2 (before `out vec4 fragColor;`); the user's own
1227
+ float;` at line 2 (before `out vec4 fragColor;`); the user's own
1061
1228
  precision declaration further down still applies to their code via
1062
1229
  the standard last-precision-wins rule. No semantic change for
1063
1230
  user-provided shader logic; previously-broken shaders with custom
@@ -1256,7 +1423,7 @@ app.backend.setCursor('pointer');
1256
1423
  const cursor = app.backend.cursor;
1257
1424
 
1258
1425
  // After:
1259
- app.setCursor('pointer'); // or
1426
+ app.setCursor('pointer'); // or
1260
1427
  app.cursor = 'pointer';
1261
1428
  const cursor = app.cursor;
1262
1429
  ```
@@ -1264,14 +1431,14 @@ const cursor = app.cursor;
1264
1431
  ```ts
1265
1432
  // New: react to backend loss
1266
1433
  app.onBackendLost.add(() => {
1267
- showReloadDialog();
1434
+ showReloadDialog();
1268
1435
  });
1269
1436
 
1270
1437
  // Or backend-specific:
1271
1438
  if (app.backend.backendType === RenderBackendType.WebGpu) {
1272
- (app.backend as WebGpuBackend).onDeviceLost.add((info) => {
1273
- console.error('GPU device lost:', info.message, info.reason);
1274
- });
1439
+ (app.backend as WebGpuBackend).onDeviceLost.add(info => {
1440
+ console.error('GPU device lost:', info.message, info.reason);
1441
+ });
1275
1442
  }
1276
1443
  ```
1277
1444
 
@@ -1380,9 +1547,9 @@ etc.).
1380
1547
  separate `WebGpuShaderFilter`.
1381
1548
  - **Backend guard messages updated**:
1382
1549
  - `WebGl2ShaderFilter` on WebGPU: `'WebGl2ShaderFilter requires the
1383
- WebGL2 backend. Use WebGpuShaderFilter on WebGPU.'`
1550
+ WebGL2 backend. Use WebGpuShaderFilter on WebGPU.'`
1384
1551
  - `WebGpuShaderFilter` on WebGL2: `'WebGpuShaderFilter requires the
1385
- WebGPU backend. Use WebGl2ShaderFilter on WebGL2.'`
1552
+ WebGPU backend. Use WebGl2ShaderFilter on WebGL2.'`
1386
1553
 
1387
1554
  `ShaderFilterUniformValue` (the polymorphic uniform value type) is
1388
1555
  **unchanged** and shared between both backends — same value shapes
@@ -1443,7 +1610,7 @@ LUT color grading, chromatic aberration, etc.
1443
1610
  via property assignment; flushed before each apply():
1444
1611
  ```ts
1445
1612
  filter.uniforms.uTime = performance.now() / 1000;
1446
- filter.uniforms.uColor = [1, 0.5, 0, 1]; // vec4
1613
+ filter.uniforms.uColor = [1, 0.5, 0, 1]; // vec4
1447
1614
  ```
1448
1615
  - **Polymorphic uniform values**: scalar `number`, tuple `[a, b]` /
1449
1616
  `[a, b, c]` / `[a, b, c, d]`, `Float32Array` / `Int32Array`, or
@@ -1458,8 +1625,8 @@ LUT color grading, chromatic aberration, etc.
1458
1625
 
1459
1626
  - **WebGL2-only in V1.** Constructor accepts `wgsl` source, but `apply()`
1460
1627
  on the WebGPU backend throws `'ShaderFilter does not yet support the
1461
- WebGPU backend. WGSL support is planned for a future release. Use the
1462
- WebGL2 backend for now.'` Document this limitation; reasoning: WebGPU
1628
+ WebGPU backend. WGSL support is planned for a future release. Use the
1629
+ WebGL2 backend for now.'` Document this limitation; reasoning: WebGPU
1463
1630
  requires a separate WGSL pipeline implementation that's substantial
1464
1631
  on its own. Coming when there's concrete user demand.
1465
1632
  - `fragmentSource` is required at construction. Constructor throws if
@@ -1476,7 +1643,7 @@ LUT color grading, chromatic aberration, etc.
1476
1643
  import { ShaderFilter } from '@codexo/exojs';
1477
1644
 
1478
1645
  const filter = new ShaderFilter({
1479
- fragmentSource: `#version 300 es
1646
+ fragmentSource: `#version 300 es
1480
1647
  precision highp float;
1481
1648
  in vec2 vUv;
1482
1649
  uniform sampler2D uTexture;
@@ -1489,15 +1656,15 @@ const filter = new ShaderFilter({
1489
1656
  outColor = texture(uTexture, uv);
1490
1657
  }
1491
1658
  `,
1492
- uniforms: {
1493
- uTime: 0,
1494
- },
1659
+ uniforms: {
1660
+ uTime: 0,
1661
+ },
1495
1662
  });
1496
1663
 
1497
1664
  sprite.filters = [filter];
1498
1665
 
1499
- app.onFrame.add((delta) => {
1500
- filter.uniforms.uTime = performance.now() / 1000;
1666
+ app.onFrame.add(delta => {
1667
+ filter.uniforms.uTime = performance.now() / 1000;
1501
1668
  });
1502
1669
  ```
1503
1670
 
@@ -1583,10 +1750,10 @@ const spectrum = analyser.getSpectrum();
1583
1750
  const waveform = analyser.getWaveform();
1584
1751
 
1585
1752
  // Now also possible:
1586
- analyser.source = mediaStream; // Mic input
1753
+ analyser.source = mediaStream; // Mic input
1587
1754
  analyser.source = app.audio.master; // Whole mix
1588
- analyser.getBandEnergy(20, 200); // Bass energy 0..1
1589
- analyser.getLowMidHigh(); // {low, mid, high}
1755
+ analyser.getBandEnergy(20, 200); // Bass energy 0..1
1756
+ analyser.getLowMidHigh(); // {low, mid, high}
1590
1757
  ```
1591
1758
 
1592
1759
  ```ts
@@ -1596,12 +1763,12 @@ detector.source = music;
1596
1763
  await detector.ready;
1597
1764
 
1598
1765
  detector.onBeat.add(({ audioTime, tempo, isDownbeat, energy }) => {
1599
- sprite.scale.set(1.5);
1600
- new Tween().target(sprite.scale).to({x: 1, y: 1}).duration(200).start();
1766
+ sprite.scale.set(1.5);
1767
+ new Tween().target(sprite.scale).to({ x: 1, y: 1 }).duration(200).start();
1601
1768
  });
1602
1769
 
1603
1770
  detector.onDownbeat.add(() => {
1604
- boss.attack(); // syncs exactly to "the 1" of each bar
1771
+ boss.attack(); // syncs exactly to "the 1" of each bar
1605
1772
  });
1606
1773
  ```
1607
1774
 
@@ -1770,22 +1937,22 @@ breaking change.
1770
1937
 
1771
1938
  ```ts
1772
1939
  // Before:
1773
- sound.play(); // singleton — second call replaces first
1774
- sound.playPooled(); // multi-instance — concurrent plays
1940
+ sound.play(); // singleton — second call replaces first
1941
+ sound.playPooled(); // multi-instance — concurrent plays
1775
1942
 
1776
1943
  // After:
1777
- sound.play(); // multi-instance — concurrent plays (default!)
1944
+ sound.play(); // multi-instance — concurrent plays (default!)
1778
1945
  sound.play({ replace: true }); // singleton — equivalent of old play()
1779
1946
  ```
1780
1947
 
1781
1948
  ```ts
1782
1949
  // Before — direct destination routing was implicit:
1783
1950
  const sound = new Sound(buffer);
1784
- sound.play(); // → audioContext.destination
1951
+ sound.play(); // → audioContext.destination
1785
1952
 
1786
1953
  // After — routes through the soundBus by default:
1787
1954
  const sound = new Sound(buffer);
1788
- sound.play(); // → app.audio.sound → app.audio.master → destination
1955
+ sound.play(); // → app.audio.sound → app.audio.master → destination
1789
1956
 
1790
1957
  // Override to a custom bus:
1791
1958
  const dialogueBus = new AudioBus('dialogue', { parent: app.audio.master });
@@ -1796,8 +1963,8 @@ sound.bus = dialogueBus;
1796
1963
  ```ts
1797
1964
  // Spatial audio:
1798
1965
  const explosion = new Sound(buffer);
1799
- explosion.position = { x: 200, y: 100 }; // becomes spatial
1800
- app.audio.listener.target = playerSprite; // ears follow player
1966
+ explosion.position = { x: 200, y: 100 }; // becomes spatial
1967
+ app.audio.listener.target = playerSprite; // ears follow player
1801
1968
 
1802
1969
  explosion.play();
1803
1970
  // → routes through equalpower panner with distance falloff
@@ -1834,7 +2001,7 @@ infrastructure. Pure additive — no behavior changes for existing code.
1834
2001
  **world-space position** via `getGlobalTransform()`, so following a
1835
2002
  Sprite nested under a translated/rotated Container works correctly.
1836
2003
  New exported type `ViewFollowTarget = SceneNode | { x: number; y:
1837
- number } | null`.
2004
+ number } | null`.
1838
2005
  - **Audio fade helpers on `AbstractMedia`** — both `Sound` and `Music`
1839
2006
  inherit:
1840
2007
  - `fadeIn(durationMs): this` — ramps gain from 0 to current volume.
@@ -1901,7 +2068,7 @@ detection. Pure performance change — no public API surface changes.
1901
2068
  components. Recomputes only when the sprite's transform or local
1902
2069
  bounds change. Previously had a `// todo cache this` comment.
1903
2070
  - **`Sprite.getNormals()`** returns a stable `[Vector, Vector,
1904
- Vector, Vector]` array. The four `Vector` instances are reused
2071
+ Vector, Vector]` array. The four `Vector` instances are reused
1905
2072
  across calls; previously each call allocated four new `Vector`s.
1906
2073
  Recomputes only when vertices change. Reduces GC pressure in
1907
2074
  collision-detection hot paths.
@@ -1983,7 +2150,7 @@ per-frame application hook.
1983
2150
 
1984
2151
  - **`Application.debug` removed** — was added in 0.6.15. Apps that
1985
2152
  used `app.debug.show()` must migrate to `import { DebugOverlay }
1986
- from '@codexo/exojs/debug'` and instantiate manually. **Breaking
2153
+ from '@codexo/exojs/debug'` and instantiate manually. **Breaking
1987
2154
  change**, but the affected window is one day (0.6.15 → 0.6.17).
1988
2155
 
1989
2156
  ### Notes
@@ -2080,7 +2247,7 @@ zero cost when not shown.
2080
2247
 
2081
2248
  Reshapes the interaction system around a per-frame tick and adds an
2082
2249
  opt-in drag-and-drop helper. The public per-node signal API from 0.6.13
2083
- is unchanged; only event *cadence* and a new `draggable` flag.
2250
+ is unchanged; only event _cadence_ and a new `draggable` flag.
2084
2251
 
2085
2252
  ### Added
2086
2253
 
@@ -2216,12 +2383,13 @@ existing surface changes shape.
2216
2383
  properties on any target object:
2217
2384
 
2218
2385
  ```ts
2219
- app.tweens.create(sprite)
2220
- .to({ x: 100, alpha: 0.5 }, 1.0) // 1 second
2221
- .easing(Ease.cubicOut)
2222
- .delay(0.2)
2223
- .onComplete(() => console.log('done'))
2224
- .start();
2386
+ app.tweens
2387
+ .create(sprite)
2388
+ .to({ x: 100, alpha: 0.5 }, 1.0) // 1 second
2389
+ .easing(Ease.cubicOut)
2390
+ .delay(0.2)
2391
+ .onComplete(() => console.log('done'))
2392
+ .start();
2225
2393
  ```
2226
2394
 
2227
2395
  Lifecycle: `Idle → Active → Complete | Stopped` (with
@@ -2233,6 +2401,7 @@ existing surface changes shape.
2233
2401
  interpolation), `onUpdate` (per frame), `onRepeat` (cycle
2234
2402
  boundaries), `onComplete` (final cycle ends naturally).
2235
2403
  `stop()` does NOT fire `onComplete`.
2404
+
2236
2405
  - **`TweenManager` class.** Owns active tweens and ticks them
2237
2406
  from `Application.update()`. Use `app.tweens.create(target)` to
2238
2407
  spawn-and-register a tween in one call; `app.tweens.add(tween)`
@@ -2328,7 +2497,7 @@ one atlas — memory-efficient at scale, single drawcall per Text.
2328
2497
 
2329
2498
  - **`DynamicGlyphAtlas`** — public class. Constructor takes
2330
2499
  `width = 1024, height = 1024`. Has `getGlyph(char, family, size,
2331
- weight, style) → GlyphInfo` (cached or rasterizes), `clear()` to
2500
+ weight, style) → GlyphInfo` (cached or rasterizes), `clear()` to
2332
2501
  reset, and `texture` for binding to a Mesh. Internal shelf
2333
2502
  bin-packing; throws on atlas-full (LRU eviction is V2).
2334
2503
  - **`layoutText(text, style, atlas)`** — pure function. Returns
@@ -2340,7 +2509,7 @@ one atlas — memory-efficient at scale, single drawcall per Text.
2340
2509
  their own atlas / layout pipelines.
2341
2510
  - **TextStyle gets `fillColor: Color`** (defaults to white, used
2342
2511
  via mesh.tint after glyph rasterization), **`fontStyle: 'normal'
2343
- | 'italic'`**, and **`lineHeight: number`** (multiplied by
2512
+ | 'italic'`**, and **`lineHeight: number`** (multiplied by
2344
2513
  fontSize for line spacing, defaults to 1.2). `align` field is
2345
2514
  now strongly typed as `TextAlignment`.
2346
2515
 
@@ -2370,8 +2539,8 @@ one atlas — memory-efficient at scale, single drawcall per Text.
2370
2539
  `document.createElement('canvas')` (works in jsdom / older
2371
2540
  browsers).
2372
2541
  - First-render of a never-seen glyph costs one canvas2d round-trip
2373
- + texture re-upload. Cached glyphs are zero-cost on subsequent
2374
- renders.
2542
+ - texture re-upload. Cached glyphs are zero-cost on subsequent
2543
+ renders.
2375
2544
  - Per-character animation, MSDF rendering, word-wrap, BiDi, and
2376
2545
  text outlines / drop-shadows are all V2.
2377
2546
 
@@ -2540,7 +2709,7 @@ one unified rendering path for everything triangle-shaped.
2540
2709
  (`buildLine`, `buildPath`, `buildCircle`, `buildEllipse`,
2541
2710
  `buildRectangle`, `buildPolygon`, `buildStar`) now return a
2542
2711
  `MeshGeometryData` plain object — `{ vertices: Float32Array,
2543
- indices: Uint16Array, points: Array<number> }` — directly suitable
2712
+ indices: Uint16Array, points: Array<number> }` — directly suitable
2544
2713
  for `new Mesh({ ... })`.
2545
2714
  - **`WebGl2PrimitiveRenderer` and `WebGpuPrimitiveRenderer` removed.**
2546
2715
  Their work moved entirely into the existing `*MeshRenderer`s. Both
@@ -2569,18 +2738,14 @@ one unified rendering path for everything triangle-shaped.
2569
2738
  // Before (0.6.4)
2570
2739
  import { DrawableShape, Geometry, RenderingPrimitives, Color } from '@codexo/exojs';
2571
2740
 
2572
- const shape = new DrawableShape(
2573
- new Geometry({ vertices: [0, 0, 100, 0, 50, 100], indices: [0, 1, 2] }),
2574
- Color.red,
2575
- RenderingPrimitives.Triangles,
2576
- );
2741
+ const shape = new DrawableShape(new Geometry({ vertices: [0, 0, 100, 0, 50, 100], indices: [0, 1, 2] }), Color.red, RenderingPrimitives.Triangles);
2577
2742
 
2578
2743
  // After (0.6.5)
2579
2744
  import { Mesh, Color } from '@codexo/exojs';
2580
2745
 
2581
2746
  const mesh = new Mesh({
2582
- vertices: new Float32Array([0, 0, 100, 0, 50, 100]),
2583
- indices: new Uint16Array([0, 1, 2]),
2747
+ vertices: new Float32Array([0, 0, 100, 0, 50, 100]),
2748
+ indices: new Uint16Array([0, 1, 2]),
2584
2749
  });
2585
2750
  mesh.tint = Color.red;
2586
2751
  ```
@@ -2656,13 +2821,13 @@ match the rest of ExoJS.
2656
2821
  ```ts
2657
2822
  // Before (0.6.3)
2658
2823
  import { capabilities, isSupported } from '@codexo/exojs';
2659
- if (capabilities.webgpu) startWebGpu(); // false positives possible
2824
+ if (capabilities.webgpu) startWebGpu(); // false positives possible
2660
2825
  if (isSupported('touch')) showTouchUi();
2661
2826
 
2662
2827
  // After (0.6.4)
2663
2828
  import { Capabilities } from '@codexo/exojs';
2664
2829
  const caps = await Capabilities.ready;
2665
- if (caps.webgpuAdapter) startWebGpu(); // strict adapter check
2830
+ if (caps.webgpuAdapter) startWebGpu(); // strict adapter check
2666
2831
  if (caps.touch) showTouchUi();
2667
2832
 
2668
2833
  // Or via Application after start:
@@ -2782,12 +2947,12 @@ and breaks freely between minors.
2782
2947
  - **`Scene` is class-only; the plain-object definition constructor is
2783
2948
  gone.** `new Scene({ update() { ... } })` no longer works. Subclass
2784
2949
  to define a scene — `class GameScene extends Scene { override
2785
- update(...) { ... } }` for named scenes, `new class extends Scene
2786
- { ... }` for one-offs. The `SceneData` interface and
2950
+ update(...) { ... } }` for named scenes, `new class extends Scene
2951
+ { ... }` for one-offs. The `SceneData` interface and
2787
2952
  `SceneInstance<T>` type alias are removed (they only existed to
2788
2953
  type the spread-into-`this` constructor). Internal Scene fields
2789
2954
  move from ECMAScript `#`-private to TS `protected _app/_root/
2790
- _stackMode/_inputMode` — subclasses can now reach internal state
2955
+ _stackMode/_inputMode` — subclasses can now reach internal state
2791
2956
  directly when they need to.
2792
2957
  - **npm package shape simplified.** Dropped: `dist/exo.global.js` /
2793
2958
  `dist/exo.global.min.js` (legacy IIFE for `<script>` use) and
@@ -2848,33 +3013,49 @@ and breaks freely between minors.
2848
3013
  ```ts
2849
3014
  // Before (0.5.x)
2850
3015
  class GameScene extends Scene {
2851
- override draw(runtime: SceneRenderRuntime): void {
2852
- this.root.render(runtime);
2853
- }
3016
+ override draw(runtime: SceneRenderRuntime): void {
3017
+ this.root.render(runtime);
3018
+ }
2854
3019
  }
2855
3020
 
2856
3021
  const triangleRenderer = new CustomRenderer(app.renderManager);
2857
3022
 
2858
- if (app.renderManager instanceof WebGpuRenderManager) { /* ... */ }
3023
+ if (app.renderManager instanceof WebGpuRenderManager) {
3024
+ /* ... */
3025
+ }
2859
3026
 
2860
3027
  // Plain-object scene
2861
- app.start(new Scene({ update() { /* ... */ } }));
3028
+ app.start(
3029
+ new Scene({
3030
+ update() {
3031
+ /* ... */
3032
+ },
3033
+ }),
3034
+ );
2862
3035
  ```
2863
3036
 
2864
3037
  ```ts
2865
3038
  // After (0.6.0)
2866
3039
  class GameScene extends Scene {
2867
- override draw(backend: RenderBackend): void {
2868
- this.root.render(backend);
2869
- }
3040
+ override draw(backend: RenderBackend): void {
3041
+ this.root.render(backend);
3042
+ }
2870
3043
  }
2871
3044
 
2872
3045
  const triangleRenderer = new CustomRenderer(app.backend);
2873
3046
 
2874
- if (app.backend instanceof WebGpuBackend) { /* ... */ }
3047
+ if (app.backend instanceof WebGpuBackend) {
3048
+ /* ... */
3049
+ }
2875
3050
 
2876
3051
  // Anonymous-subclass scene (or named subclass)
2877
- app.start(new class extends Scene { override update() { /* ... */ } });
3052
+ app.start(
3053
+ new (class extends Scene {
3054
+ override update() {
3055
+ /* ... */
3056
+ }
3057
+ })(),
3058
+ );
2878
3059
  ```
2879
3060
 
2880
3061
  ## [0.5.1] - 2026-04-28
@@ -2968,6 +3149,7 @@ Three focused breaking changes targeted at the first pre-1.0 minor: a hierarchy-
2968
3149
  - `null` — no mask.
2969
3150
 
2970
3151
  Setting `node.mask = node` (self-mask) throws at runtime.
3152
+
2971
3153
  - **`SceneRenderRuntime` mask primitives renamed** to match the new vocabulary:
2972
3154
  - `pushMask(maskBounds)` / `popMask()` → `pushScissorRect(bounds)` / `popScissorRect()` (lower-level scissor primitive used internally by the `Rectangle` mask path).
2973
3155
  - New `composeWithAlphaMask(content, mask, x, y, width, height, blendMode)` — used internally by the Texture/RenderTexture/RenderNode mask paths.
@@ -2985,19 +3167,19 @@ Three focused breaking changes targeted at the first pre-1.0 minor: a hierarchy-
2985
3167
 
2986
3168
  ### Migration
2987
3169
 
2988
- | Before (0.4.x) | After |
2989
- |---|---|
2990
- | `import { Transformable } from '@codexo/exojs'`; `class X extends Transformable` | `import { SceneNode } from '@codexo/exojs'`; `class X extends SceneNode` |
2991
- | `import { TransformableFlags } from '@codexo/exojs'` | Internal flag enum is no longer public; use SceneNode's high-level transform accessors instead. |
2992
- | `node.mask = anyShapeNode` *(silently clipped to bounding rect)* | `node.mask = anyShapeNode` *(now a real shape mask via alpha compositing — except bare SceneNode which is rejected at compile time)* |
2993
- | Want fast axis-aligned clipping? | `node.mask = new Rectangle(x, y, w, h)` |
2994
- | Want to clip with a texture's alpha channel? | `node.mask = texture` or `node.mask = renderTexture` |
2995
- | Want a transformed/positioned alpha mask? | `node.mask = new Sprite(texture)` (Sprite's transform/position/scale apply to the mask source) |
2996
- | `runtime.pushMask(rect)` / `runtime.popMask()` | `runtime.pushScissorRect(rect)` / `runtime.popScissorRect()` (renamed; behavior unchanged) |
2997
- | `class Group extends SceneNode { override render() {...} }` | `class Group extends RenderNode { override render() {...} }` |
2998
- | `class CustomContainer extends Container { override addChild(child: SceneNode) {...} }` | `class CustomContainer extends Container { override addChild(child: RenderNode) {...} }` |
2999
- | `Scene.create({ update() {...} })` | `new Scene({ update() {...} })` (drop-in replacement; same `this` typing via `ThisType<Scene & T>`) |
3000
- | `Scene.create({})` | `new Scene()` |
3170
+ | Before (0.4.x) | After |
3171
+ | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
3172
+ | `import { Transformable } from '@codexo/exojs'`; `class X extends Transformable` | `import { SceneNode } from '@codexo/exojs'`; `class X extends SceneNode` |
3173
+ | `import { TransformableFlags } from '@codexo/exojs'` | Internal flag enum is no longer public; use SceneNode's high-level transform accessors instead. |
3174
+ | `node.mask = anyShapeNode` _(silently clipped to bounding rect)_ | `node.mask = anyShapeNode` _(now a real shape mask via alpha compositing — except bare SceneNode which is rejected at compile time)_ |
3175
+ | Want fast axis-aligned clipping? | `node.mask = new Rectangle(x, y, w, h)` |
3176
+ | Want to clip with a texture's alpha channel? | `node.mask = texture` or `node.mask = renderTexture` |
3177
+ | Want a transformed/positioned alpha mask? | `node.mask = new Sprite(texture)` (Sprite's transform/position/scale apply to the mask source) |
3178
+ | `runtime.pushMask(rect)` / `runtime.popMask()` | `runtime.pushScissorRect(rect)` / `runtime.popScissorRect()` (renamed; behavior unchanged) |
3179
+ | `class Group extends SceneNode { override render() {...} }` | `class Group extends RenderNode { override render() {...} }` |
3180
+ | `class CustomContainer extends Container { override addChild(child: SceneNode) {...} }` | `class CustomContainer extends Container { override addChild(child: RenderNode) {...} }` |
3181
+ | `Scene.create({ update() {...} })` | `new Scene({ update() {...} })` (drop-in replacement; same `this` typing via `ThisType<Scene & T>`) |
3182
+ | `Scene.create({})` | `new Scene()` |
3001
3183
 
3002
3184
  No deprecated aliases are provided. The migration is mechanical and the project is pre-1.0 with explicit "may break between minors" policy.
3003
3185