@codexo/exojs 0.8.0 → 0.8.2

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 (486) hide show
  1. package/CHANGELOG.md +318 -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 +1 -1
  15. package/dist/esm/audio/AudioAnalyser.js +2 -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 +4 -4
  26. package/dist/esm/audio/BeatDetector.js +68 -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/tempogram.d.ts +2 -2
  45. package/dist/esm/audio/filters/ChorusFilter.js +12 -4
  46. package/dist/esm/audio/filters/ChorusFilter.js.map +1 -1
  47. package/dist/esm/audio/filters/CompressorFilter.d.ts +9 -0
  48. package/dist/esm/audio/filters/CompressorFilter.js +11 -0
  49. package/dist/esm/audio/filters/CompressorFilter.js.map +1 -1
  50. package/dist/esm/audio/filters/DelayFilter.js.map +1 -1
  51. package/dist/esm/audio/filters/DuckingFilter.d.ts +1 -1
  52. package/dist/esm/audio/filters/DuckingFilter.js +13 -5
  53. package/dist/esm/audio/filters/DuckingFilter.js.map +1 -1
  54. package/dist/esm/audio/filters/EqualizerFilter.js.map +1 -1
  55. package/dist/esm/audio/filters/GranularFilter.js +30 -14
  56. package/dist/esm/audio/filters/GranularFilter.js.map +1 -1
  57. package/dist/esm/audio/filters/HighpassFilter.js.map +1 -1
  58. package/dist/esm/audio/filters/LowpassFilter.js.map +1 -1
  59. package/dist/esm/audio/filters/PitchShiftFilter.js +14 -10
  60. package/dist/esm/audio/filters/PitchShiftFilter.js.map +1 -1
  61. package/dist/esm/audio/filters/ReverbFilter.js.map +1 -1
  62. package/dist/esm/audio/filters/VocoderFilter.d.ts +2 -2
  63. package/dist/esm/audio/filters/VocoderFilter.js +20 -12
  64. package/dist/esm/audio/filters/VocoderFilter.js.map +1 -1
  65. package/dist/esm/audio/filters/WorkletFilter.js +5 -6
  66. package/dist/esm/audio/filters/WorkletFilter.js.map +1 -1
  67. package/dist/esm/audio/filters/index.d.ts +7 -7
  68. package/dist/esm/audio/index.d.ts +9 -9
  69. package/dist/esm/audio/worklet/registerWorklet.js +7 -3
  70. package/dist/esm/audio/worklet/registerWorklet.js.map +1 -1
  71. package/dist/esm/core/Application.d.ts +13 -13
  72. package/dist/esm/core/Application.js +24 -16
  73. package/dist/esm/core/Application.js.map +1 -1
  74. package/dist/esm/core/Bounds.d.ts +1 -1
  75. package/dist/esm/core/Bounds.js +1 -3
  76. package/dist/esm/core/Bounds.js.map +1 -1
  77. package/dist/esm/core/Clock.js +1 -1
  78. package/dist/esm/core/Clock.js.map +1 -1
  79. package/dist/esm/core/Color.js +2 -5
  80. package/dist/esm/core/Color.js.map +1 -1
  81. package/dist/esm/core/Scene.d.ts +10 -10
  82. package/dist/esm/core/Scene.js +1 -1
  83. package/dist/esm/core/Scene.js.map +1 -1
  84. package/dist/esm/core/SceneManager.d.ts +4 -4
  85. package/dist/esm/core/SceneManager.js +39 -33
  86. package/dist/esm/core/SceneManager.js.map +1 -1
  87. package/dist/esm/core/SceneNode.d.ts +8 -8
  88. package/dist/esm/core/SceneNode.js +39 -29
  89. package/dist/esm/core/SceneNode.js.map +1 -1
  90. package/dist/esm/core/Signal.d.ts +3 -3
  91. package/dist/esm/core/Signal.js +3 -3
  92. package/dist/esm/core/Signal.js.map +1 -1
  93. package/dist/esm/core/Time.js +6 -6
  94. package/dist/esm/core/Time.js.map +1 -1
  95. package/dist/esm/core/Timer.d.ts +1 -1
  96. package/dist/esm/core/Timer.js +1 -1
  97. package/dist/esm/core/Timer.js.map +1 -1
  98. package/dist/esm/core/capabilities.js +2 -4
  99. package/dist/esm/core/capabilities.js.map +1 -1
  100. package/dist/esm/core/index.d.ts +2 -2
  101. package/dist/esm/core/utils.d.ts +4 -4
  102. package/dist/esm/core/utils.js +10 -10
  103. package/dist/esm/core/utils.js.map +1 -1
  104. package/dist/esm/debug/BoundingBoxesLayer.d.ts +3 -3
  105. package/dist/esm/debug/BoundingBoxesLayer.js +6 -13
  106. package/dist/esm/debug/BoundingBoxesLayer.js.map +1 -1
  107. package/dist/esm/debug/DebugLayer.d.ts +1 -1
  108. package/dist/esm/debug/DebugLayer.js.map +1 -1
  109. package/dist/esm/debug/DebugOverlay.d.ts +2 -2
  110. package/dist/esm/debug/DebugOverlay.js +2 -2
  111. package/dist/esm/debug/DebugOverlay.js.map +1 -1
  112. package/dist/esm/debug/HitTestLayer.d.ts +3 -3
  113. package/dist/esm/debug/HitTestLayer.js +3 -10
  114. package/dist/esm/debug/HitTestLayer.js.map +1 -1
  115. package/dist/esm/debug/PerformanceLayer.d.ts +2 -2
  116. package/dist/esm/debug/PerformanceLayer.js +6 -6
  117. package/dist/esm/debug/PerformanceLayer.js.map +1 -1
  118. package/dist/esm/debug/PointerStackLayer.d.ts +3 -3
  119. package/dist/esm/debug/PointerStackLayer.js +3 -3
  120. package/dist/esm/debug/PointerStackLayer.js.map +1 -1
  121. package/dist/esm/debug/index.d.ts +3 -3
  122. package/dist/esm/debug/index.js +3 -3
  123. package/dist/esm/index.d.ts +1 -1
  124. package/dist/esm/index.js +99 -98
  125. package/dist/esm/index.js.map +1 -1
  126. package/dist/esm/input/ArcadeStickGamepadMapping.js.map +1 -1
  127. package/dist/esm/input/GameCubeGamepadMapping.d.ts +1 -1
  128. package/dist/esm/input/GameCubeGamepadMapping.js +1 -1
  129. package/dist/esm/input/GameCubeGamepadMapping.js.map +1 -1
  130. package/dist/esm/input/Gamepad.d.ts +7 -7
  131. package/dist/esm/input/Gamepad.js +10 -6
  132. package/dist/esm/input/Gamepad.js.map +1 -1
  133. package/dist/esm/input/GamepadAxis.js +1 -1
  134. package/dist/esm/input/GamepadAxis.js.map +1 -1
  135. package/dist/esm/input/GamepadButton.js +1 -1
  136. package/dist/esm/input/GamepadButton.js.map +1 -1
  137. package/dist/esm/input/GamepadDefinitions.d.ts +4 -4
  138. package/dist/esm/input/GamepadDefinitions.js +12 -14
  139. package/dist/esm/input/GamepadDefinitions.js.map +1 -1
  140. package/dist/esm/input/GamepadMapping.d.ts +5 -5
  141. package/dist/esm/input/GamepadMapping.js.map +1 -1
  142. package/dist/esm/input/GamepadPromptLayouts.d.ts +2 -2
  143. package/dist/esm/input/GamepadPromptLayouts.js +8 -8
  144. package/dist/esm/input/GamepadPromptLayouts.js.map +1 -1
  145. package/dist/esm/input/GenericDualAnalogGamepadMapping.js.map +1 -1
  146. package/dist/esm/input/GestureRecognizer.d.ts +1 -1
  147. package/dist/esm/input/GestureRecognizer.js.map +1 -1
  148. package/dist/esm/input/InputBinding.d.ts +3 -3
  149. package/dist/esm/input/InputBinding.js.map +1 -1
  150. package/dist/esm/input/InputManager.d.ts +9 -9
  151. package/dist/esm/input/InputManager.js +25 -16
  152. package/dist/esm/input/InputManager.js.map +1 -1
  153. package/dist/esm/input/InteractionEvent.d.ts +1 -1
  154. package/dist/esm/input/InteractionEvent.js.map +1 -1
  155. package/dist/esm/input/InteractionManager.d.ts +2 -2
  156. package/dist/esm/input/InteractionManager.js +25 -16
  157. package/dist/esm/input/InteractionManager.js.map +1 -1
  158. package/dist/esm/input/JoyConLeftGamepadMapping.js.map +1 -1
  159. package/dist/esm/input/JoyConRightGamepadMapping.js.map +1 -1
  160. package/dist/esm/input/PlayStationGamepadMapping.d.ts +1 -1
  161. package/dist/esm/input/PlayStationGamepadMapping.js +1 -1
  162. package/dist/esm/input/PlayStationGamepadMapping.js.map +1 -1
  163. package/dist/esm/input/Pointer.d.ts +2 -2
  164. package/dist/esm/input/Pointer.js +6 -6
  165. package/dist/esm/input/Pointer.js.map +1 -1
  166. package/dist/esm/input/SteamControllerGamepadMapping.d.ts +1 -1
  167. package/dist/esm/input/SteamControllerGamepadMapping.js +1 -1
  168. package/dist/esm/input/SteamControllerGamepadMapping.js.map +1 -1
  169. package/dist/esm/input/SteamDeckGamepadMapping.js.map +1 -1
  170. package/dist/esm/input/SwitchProGamepadMapping.d.ts +1 -1
  171. package/dist/esm/input/SwitchProGamepadMapping.js +1 -1
  172. package/dist/esm/input/SwitchProGamepadMapping.js.map +1 -1
  173. package/dist/esm/input/XboxGamepadMapping.d.ts +1 -1
  174. package/dist/esm/input/XboxGamepadMapping.js +1 -1
  175. package/dist/esm/input/XboxGamepadMapping.js.map +1 -1
  176. package/dist/esm/input/index.d.ts +16 -16
  177. package/dist/esm/input/interaction-hooks.js.map +1 -1
  178. package/dist/esm/input/types.js.map +1 -1
  179. package/dist/esm/math/AbstractVector.js +8 -9
  180. package/dist/esm/math/AbstractVector.js.map +1 -1
  181. package/dist/esm/math/Circle.d.ts +5 -5
  182. package/dist/esm/math/Circle.js +33 -21
  183. package/dist/esm/math/Circle.js.map +1 -1
  184. package/dist/esm/math/Collision.d.ts +2 -2
  185. package/dist/esm/math/Collision.js.map +1 -1
  186. package/dist/esm/math/Ellipse.d.ts +5 -5
  187. package/dist/esm/math/Ellipse.js +28 -19
  188. package/dist/esm/math/Ellipse.js.map +1 -1
  189. package/dist/esm/math/Flags.d.ts +4 -4
  190. package/dist/esm/math/Flags.js.map +1 -1
  191. package/dist/esm/math/Interval.js.map +1 -1
  192. package/dist/esm/math/Line.d.ts +5 -5
  193. package/dist/esm/math/Line.js +23 -15
  194. package/dist/esm/math/Line.js.map +1 -1
  195. package/dist/esm/math/Matrix.js +14 -16
  196. package/dist/esm/math/Matrix.js.map +1 -1
  197. package/dist/esm/math/ObservableSize.js.map +1 -1
  198. package/dist/esm/math/ObservableVector.d.ts +1 -1
  199. package/dist/esm/math/ObservableVector.js.map +1 -1
  200. package/dist/esm/math/PolarVector.js.map +1 -1
  201. package/dist/esm/math/Polygon.d.ts +11 -11
  202. package/dist/esm/math/Polygon.js +37 -26
  203. package/dist/esm/math/Polygon.js.map +1 -1
  204. package/dist/esm/math/PolygonLike.d.ts +1 -1
  205. package/dist/esm/math/Quadtree.js +2 -8
  206. package/dist/esm/math/Quadtree.js.map +1 -1
  207. package/dist/esm/math/Random.js +5 -5
  208. package/dist/esm/math/Random.js.map +1 -1
  209. package/dist/esm/math/Rectangle.d.ts +4 -4
  210. package/dist/esm/math/Rectangle.js +59 -41
  211. package/dist/esm/math/Rectangle.js.map +1 -1
  212. package/dist/esm/math/Segment.d.ts +1 -1
  213. package/dist/esm/math/Segment.js +4 -4
  214. package/dist/esm/math/Segment.js.map +1 -1
  215. package/dist/esm/math/ShapeLike.d.ts +1 -1
  216. package/dist/esm/math/Size.js +1 -2
  217. package/dist/esm/math/Size.js.map +1 -1
  218. package/dist/esm/math/Vector.d.ts +4 -4
  219. package/dist/esm/math/Vector.js +19 -13
  220. package/dist/esm/math/Vector.js.map +1 -1
  221. package/dist/esm/math/collision-detection.d.ts +3 -3
  222. package/dist/esm/math/collision-detection.js +49 -49
  223. package/dist/esm/math/collision-detection.js.map +1 -1
  224. package/dist/esm/math/collision-primitives.d.ts +8 -8
  225. package/dist/esm/math/collision-primitives.js +27 -33
  226. package/dist/esm/math/collision-primitives.js.map +1 -1
  227. package/dist/esm/math/geometry.d.ts +3 -3
  228. package/dist/esm/math/geometry.js +55 -48
  229. package/dist/esm/math/geometry.js.map +1 -1
  230. package/dist/esm/math/index.d.ts +16 -16
  231. package/dist/esm/math/swept-collision.d.ts +3 -3
  232. package/dist/esm/math/swept-collision.js +5 -8
  233. package/dist/esm/math/swept-collision.js.map +1 -1
  234. package/dist/esm/math/triangulate.js +34 -24
  235. package/dist/esm/math/triangulate.js.map +1 -1
  236. package/dist/esm/math/utils.d.ts +2 -2
  237. package/dist/esm/math/utils.js +7 -7
  238. package/dist/esm/math/utils.js.map +1 -1
  239. package/dist/esm/particles/ParticleSystem.d.ts +9 -9
  240. package/dist/esm/particles/ParticleSystem.js +29 -29
  241. package/dist/esm/particles/ParticleSystem.js.map +1 -1
  242. package/dist/esm/particles/distributions/BoxArea.js.map +1 -1
  243. package/dist/esm/particles/distributions/CircleArea.js.map +1 -1
  244. package/dist/esm/particles/distributions/ConeDirection.js.map +1 -1
  245. package/dist/esm/particles/distributions/Constant.js.map +1 -1
  246. package/dist/esm/particles/distributions/Curve.d.ts +1 -1
  247. package/dist/esm/particles/distributions/Curve.js.map +1 -1
  248. package/dist/esm/particles/distributions/Gradient.d.ts +1 -1
  249. package/dist/esm/particles/distributions/Gradient.js +1 -1
  250. package/dist/esm/particles/distributions/Gradient.js.map +1 -1
  251. package/dist/esm/particles/distributions/LineSegment.js.map +1 -1
  252. package/dist/esm/particles/distributions/Range.js.map +1 -1
  253. package/dist/esm/particles/distributions/VectorRange.js.map +1 -1
  254. package/dist/esm/particles/distributions/index.d.ts +9 -9
  255. package/dist/esm/particles/gpu/ParticleGpuState.d.ts +3 -3
  256. package/dist/esm/particles/gpu/ParticleGpuState.js +48 -21
  257. package/dist/esm/particles/gpu/ParticleGpuState.js.map +1 -1
  258. package/dist/esm/particles/index.d.ts +1 -1
  259. package/dist/esm/particles/modules/AlphaFadeOverLifetime.d.ts +2 -2
  260. package/dist/esm/particles/modules/AlphaFadeOverLifetime.js.map +1 -1
  261. package/dist/esm/particles/modules/ApplyForce.d.ts +1 -1
  262. package/dist/esm/particles/modules/ApplyForce.js.map +1 -1
  263. package/dist/esm/particles/modules/AttractToPoint.d.ts +1 -1
  264. package/dist/esm/particles/modules/AttractToPoint.js.map +1 -1
  265. package/dist/esm/particles/modules/BurstSpawn.d.ts +4 -4
  266. package/dist/esm/particles/modules/BurstSpawn.js +2 -2
  267. package/dist/esm/particles/modules/BurstSpawn.js.map +1 -1
  268. package/dist/esm/particles/modules/ColorOverLifetime.d.ts +2 -2
  269. package/dist/esm/particles/modules/ColorOverLifetime.js +1 -1
  270. package/dist/esm/particles/modules/ColorOverLifetime.js.map +1 -1
  271. package/dist/esm/particles/modules/ColorOverSpeed.d.ts +2 -2
  272. package/dist/esm/particles/modules/ColorOverSpeed.js +1 -1
  273. package/dist/esm/particles/modules/ColorOverSpeed.js.map +1 -1
  274. package/dist/esm/particles/modules/DeathModule.js.map +1 -1
  275. package/dist/esm/particles/modules/Drag.d.ts +1 -1
  276. package/dist/esm/particles/modules/Drag.js +1 -3
  277. package/dist/esm/particles/modules/Drag.js.map +1 -1
  278. package/dist/esm/particles/modules/OrbitalForce.d.ts +1 -1
  279. package/dist/esm/particles/modules/OrbitalForce.js.map +1 -1
  280. package/dist/esm/particles/modules/RateSpawn.d.ts +3 -3
  281. package/dist/esm/particles/modules/RateSpawn.js +2 -2
  282. package/dist/esm/particles/modules/RateSpawn.js.map +1 -1
  283. package/dist/esm/particles/modules/RepelFromPoint.d.ts +1 -1
  284. package/dist/esm/particles/modules/RepelFromPoint.js.map +1 -1
  285. package/dist/esm/particles/modules/RotateOverLifetime.d.ts +1 -1
  286. package/dist/esm/particles/modules/RotateOverLifetime.js +1 -3
  287. package/dist/esm/particles/modules/RotateOverLifetime.js.map +1 -1
  288. package/dist/esm/particles/modules/ScaleOverLifetime.d.ts +2 -2
  289. package/dist/esm/particles/modules/ScaleOverLifetime.js.map +1 -1
  290. package/dist/esm/particles/modules/SpawnModule.js.map +1 -1
  291. package/dist/esm/particles/modules/SpawnOnDeath.d.ts +1 -1
  292. package/dist/esm/particles/modules/SpawnOnDeath.js.map +1 -1
  293. package/dist/esm/particles/modules/Turbulence.d.ts +1 -1
  294. package/dist/esm/particles/modules/Turbulence.js.map +1 -1
  295. package/dist/esm/particles/modules/UpdateModule.js.map +1 -1
  296. package/dist/esm/particles/modules/VelocityOverLifetime.d.ts +2 -2
  297. package/dist/esm/particles/modules/VelocityOverLifetime.js.map +1 -1
  298. package/dist/esm/particles/modules/WgslContribution.d.ts +3 -3
  299. package/dist/esm/particles/modules/WgslContribution.js.map +1 -1
  300. package/dist/esm/particles/modules/index.d.ts +17 -17
  301. package/dist/esm/rendering/CallbackRenderPass.js.map +1 -1
  302. package/dist/esm/rendering/Container.d.ts +2 -2
  303. package/dist/esm/rendering/Container.js +10 -11
  304. package/dist/esm/rendering/Container.js.map +1 -1
  305. package/dist/esm/rendering/Drawable.js.map +1 -1
  306. package/dist/esm/rendering/RenderBackend.d.ts +6 -6
  307. package/dist/esm/rendering/RenderBackendType.js.map +1 -1
  308. package/dist/esm/rendering/RenderNode.d.ts +10 -10
  309. package/dist/esm/rendering/RenderNode.js +31 -31
  310. package/dist/esm/rendering/RenderNode.js.map +1 -1
  311. package/dist/esm/rendering/RenderStats.js.map +1 -1
  312. package/dist/esm/rendering/RenderTarget.d.ts +2 -2
  313. package/dist/esm/rendering/RenderTarget.js +5 -5
  314. package/dist/esm/rendering/RenderTarget.js.map +1 -1
  315. package/dist/esm/rendering/RenderTargetPass.d.ts +3 -3
  316. package/dist/esm/rendering/RenderTargetPass.js.map +1 -1
  317. package/dist/esm/rendering/Renderer.d.ts +2 -2
  318. package/dist/esm/rendering/RendererRegistry.d.ts +3 -3
  319. package/dist/esm/rendering/RendererRegistry.js +2 -3
  320. package/dist/esm/rendering/RendererRegistry.js.map +1 -1
  321. package/dist/esm/rendering/View.d.ts +3 -3
  322. package/dist/esm/rendering/View.js +17 -20
  323. package/dist/esm/rendering/View.js.map +1 -1
  324. package/dist/esm/rendering/filters/BlurFilter.d.ts +1 -1
  325. package/dist/esm/rendering/filters/BlurFilter.js +4 -9
  326. package/dist/esm/rendering/filters/BlurFilter.js.map +1 -1
  327. package/dist/esm/rendering/filters/ColorFilter.d.ts +1 -1
  328. package/dist/esm/rendering/filters/ColorFilter.js +3 -9
  329. package/dist/esm/rendering/filters/ColorFilter.js.map +1 -1
  330. package/dist/esm/rendering/filters/Filter.d.ts +1 -1
  331. package/dist/esm/rendering/filters/Filter.js.map +1 -1
  332. package/dist/esm/rendering/filters/LutFilter.d.ts +87 -0
  333. package/dist/esm/rendering/filters/LutFilter.js +261 -0
  334. package/dist/esm/rendering/filters/LutFilter.js.map +1 -0
  335. package/dist/esm/rendering/filters/WebGl2ShaderFilter.d.ts +2 -2
  336. package/dist/esm/rendering/filters/WebGl2ShaderFilter.js +7 -14
  337. package/dist/esm/rendering/filters/WebGl2ShaderFilter.js.map +1 -1
  338. package/dist/esm/rendering/filters/WebGpuShaderFilter.d.ts +1 -1
  339. package/dist/esm/rendering/filters/WebGpuShaderFilter.js +11 -10
  340. package/dist/esm/rendering/filters/WebGpuShaderFilter.js.map +1 -1
  341. package/dist/esm/rendering/index.d.ts +28 -27
  342. package/dist/esm/rendering/mesh/Mesh.d.ts +49 -1
  343. package/dist/esm/rendering/mesh/Mesh.js +3 -1
  344. package/dist/esm/rendering/mesh/Mesh.js.map +1 -1
  345. package/dist/esm/rendering/primitives/Graphics.d.ts +3 -3
  346. package/dist/esm/rendering/primitives/Graphics.js +12 -12
  347. package/dist/esm/rendering/primitives/Graphics.js.map +1 -1
  348. package/dist/esm/rendering/shader/Shader.js.map +1 -1
  349. package/dist/esm/rendering/shader/ShaderAttribute.js.map +1 -1
  350. package/dist/esm/rendering/shader/ShaderUniform.js.map +1 -1
  351. package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.js +6 -8
  352. package/dist/esm/rendering/shader/upgradeFragmentShaderToGl300.js.map +1 -1
  353. package/dist/esm/rendering/sprite/AnimatedSprite.d.ts +3 -3
  354. package/dist/esm/rendering/sprite/AnimatedSprite.js.map +1 -1
  355. package/dist/esm/rendering/sprite/Sprite.d.ts +4 -4
  356. package/dist/esm/rendering/sprite/Sprite.js +51 -35
  357. package/dist/esm/rendering/sprite/Sprite.js.map +1 -1
  358. package/dist/esm/rendering/sprite/Spritesheet.d.ts +5 -9
  359. package/dist/esm/rendering/sprite/Spritesheet.js +1 -1
  360. package/dist/esm/rendering/sprite/Spritesheet.js.map +1 -1
  361. package/dist/esm/rendering/text/DynamicGlyphAtlas.js +3 -9
  362. package/dist/esm/rendering/text/DynamicGlyphAtlas.js.map +1 -1
  363. package/dist/esm/rendering/text/Text.js +9 -9
  364. package/dist/esm/rendering/text/Text.js.map +1 -1
  365. package/dist/esm/rendering/text/TextLayout.d.ts +2 -2
  366. package/dist/esm/rendering/text/TextLayout.js.map +1 -1
  367. package/dist/esm/rendering/text/TextStyle.js.map +1 -1
  368. package/dist/esm/rendering/text/atlas-singleton.js.map +1 -1
  369. package/dist/esm/rendering/texture/RenderTexture.d.ts +1 -1
  370. package/dist/esm/rendering/texture/RenderTexture.js +4 -1
  371. package/dist/esm/rendering/texture/RenderTexture.js.map +1 -1
  372. package/dist/esm/rendering/texture/Sampler.js.map +1 -1
  373. package/dist/esm/rendering/texture/Texture.d.ts +2 -2
  374. package/dist/esm/rendering/texture/Texture.js +8 -5
  375. package/dist/esm/rendering/texture/Texture.js.map +1 -1
  376. package/dist/esm/rendering/types.js.map +1 -1
  377. package/dist/esm/rendering/utils.js.map +1 -1
  378. package/dist/esm/rendering/video/Video.d.ts +3 -3
  379. package/dist/esm/rendering/video/Video.js +7 -6
  380. package/dist/esm/rendering/video/Video.js.map +1 -1
  381. package/dist/esm/rendering/webgl2/AbstractWebGl2BatchedRenderer.d.ts +6 -6
  382. package/dist/esm/rendering/webgl2/AbstractWebGl2BatchedRenderer.js +7 -10
  383. package/dist/esm/rendering/webgl2/AbstractWebGl2BatchedRenderer.js.map +1 -1
  384. package/dist/esm/rendering/webgl2/AbstractWebGl2Renderer.d.ts +1 -1
  385. package/dist/esm/rendering/webgl2/AbstractWebGl2Renderer.js +1 -2
  386. package/dist/esm/rendering/webgl2/AbstractWebGl2Renderer.js.map +1 -1
  387. package/dist/esm/rendering/webgl2/WebGl2Backend.d.ts +11 -11
  388. package/dist/esm/rendering/webgl2/WebGl2Backend.js +19 -21
  389. package/dist/esm/rendering/webgl2/WebGl2Backend.js.map +1 -1
  390. package/dist/esm/rendering/webgl2/WebGl2MaskCompositor.d.ts +2 -2
  391. package/dist/esm/rendering/webgl2/WebGl2MaskCompositor.js +6 -8
  392. package/dist/esm/rendering/webgl2/WebGl2MaskCompositor.js.map +1 -1
  393. package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.d.ts +7 -4
  394. package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.js +110 -43
  395. package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.js.map +1 -1
  396. package/dist/esm/rendering/webgl2/WebGl2ParticleRenderer.d.ts +1 -1
  397. package/dist/esm/rendering/webgl2/WebGl2ParticleRenderer.js +10 -18
  398. package/dist/esm/rendering/webgl2/WebGl2ParticleRenderer.js.map +1 -1
  399. package/dist/esm/rendering/webgl2/WebGl2RenderBuffer.d.ts +1 -1
  400. package/dist/esm/rendering/webgl2/WebGl2RenderBuffer.js.map +1 -1
  401. package/dist/esm/rendering/webgl2/WebGl2ShaderBlock.js.map +1 -1
  402. package/dist/esm/rendering/webgl2/WebGl2ShaderMappings.js.map +1 -1
  403. package/dist/esm/rendering/webgl2/WebGl2ShaderProgram.js +54 -22
  404. package/dist/esm/rendering/webgl2/WebGl2ShaderProgram.js.map +1 -1
  405. package/dist/esm/rendering/webgl2/WebGl2SpriteRenderer.d.ts +1 -1
  406. package/dist/esm/rendering/webgl2/WebGl2SpriteRenderer.js +11 -14
  407. package/dist/esm/rendering/webgl2/WebGl2SpriteRenderer.js.map +1 -1
  408. package/dist/esm/rendering/webgl2/WebGl2VertexArrayObject.d.ts +1 -1
  409. package/dist/esm/rendering/webgl2/WebGl2VertexArrayObject.js.map +1 -1
  410. package/dist/esm/rendering/webgpu/AbstractWebGpuRenderer.d.ts +1 -1
  411. package/dist/esm/rendering/webgpu/AbstractWebGpuRenderer.js +1 -2
  412. package/dist/esm/rendering/webgpu/AbstractWebGpuRenderer.js.map +1 -1
  413. package/dist/esm/rendering/webgpu/WebGpuBackend.d.ts +7 -7
  414. package/dist/esm/rendering/webgpu/WebGpuBackend.js +44 -30
  415. package/dist/esm/rendering/webgpu/WebGpuBackend.js.map +1 -1
  416. package/dist/esm/rendering/webgpu/WebGpuBlendState.js.map +1 -1
  417. package/dist/esm/rendering/webgpu/WebGpuMaskCompositor.d.ts +2 -2
  418. package/dist/esm/rendering/webgpu/WebGpuMaskCompositor.js +1 -3
  419. package/dist/esm/rendering/webgpu/WebGpuMaskCompositor.js.map +1 -1
  420. package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.d.ts +2 -2
  421. package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.js +25 -23
  422. package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.js.map +1 -1
  423. package/dist/esm/rendering/webgpu/WebGpuParticleRenderer.d.ts +1 -1
  424. package/dist/esm/rendering/webgpu/WebGpuParticleRenderer.js +100 -56
  425. package/dist/esm/rendering/webgpu/WebGpuParticleRenderer.js.map +1 -1
  426. package/dist/esm/rendering/webgpu/WebGpuSpriteRenderer.d.ts +2 -2
  427. package/dist/esm/rendering/webgpu/WebGpuSpriteRenderer.js +45 -45
  428. package/dist/esm/rendering/webgpu/WebGpuSpriteRenderer.js.map +1 -1
  429. package/dist/esm/rendering/webgpu/compute/WebGpuComputePipeline.d.ts +1 -1
  430. package/dist/esm/rendering/webgpu/compute/index.d.ts +2 -2
  431. package/dist/esm/resources/AbstractAssetFactory.d.ts +1 -1
  432. package/dist/esm/resources/AbstractAssetFactory.js.map +1 -1
  433. package/dist/esm/resources/AssetManifest.d.ts +1 -1
  434. package/dist/esm/resources/AssetManifest.js +2 -2
  435. package/dist/esm/resources/AssetManifest.js.map +1 -1
  436. package/dist/esm/resources/CacheFirstStrategy.d.ts +2 -2
  437. package/dist/esm/resources/CacheFirstStrategy.js.map +1 -1
  438. package/dist/esm/resources/CacheStrategy.d.ts +1 -1
  439. package/dist/esm/resources/FactoryRegistry.d.ts +1 -1
  440. package/dist/esm/resources/FactoryRegistry.js +2 -3
  441. package/dist/esm/resources/FactoryRegistry.js.map +1 -1
  442. package/dist/esm/resources/IndexedDbDatabase.d.ts +1 -1
  443. package/dist/esm/resources/IndexedDbDatabase.js +11 -14
  444. package/dist/esm/resources/IndexedDbDatabase.js.map +1 -1
  445. package/dist/esm/resources/IndexedDbStore.d.ts +1 -1
  446. package/dist/esm/resources/IndexedDbStore.js +2 -7
  447. package/dist/esm/resources/IndexedDbStore.js.map +1 -1
  448. package/dist/esm/resources/Loader.d.ts +9 -9
  449. package/dist/esm/resources/Loader.js +48 -35
  450. package/dist/esm/resources/Loader.js.map +1 -1
  451. package/dist/esm/resources/NetworkOnlyStrategy.d.ts +2 -2
  452. package/dist/esm/resources/NetworkOnlyStrategy.js.map +1 -1
  453. package/dist/esm/resources/factories/BinaryFactory.js.map +1 -1
  454. package/dist/esm/resources/factories/FontFactory.js +1 -1
  455. package/dist/esm/resources/factories/FontFactory.js.map +1 -1
  456. package/dist/esm/resources/factories/ImageFactory.js +4 -4
  457. package/dist/esm/resources/factories/ImageFactory.js.map +1 -1
  458. package/dist/esm/resources/factories/JsonFactory.d.ts +1 -1
  459. package/dist/esm/resources/factories/JsonFactory.js +1 -1
  460. package/dist/esm/resources/factories/JsonFactory.js.map +1 -1
  461. package/dist/esm/resources/factories/MusicFactory.d.ts +1 -1
  462. package/dist/esm/resources/factories/MusicFactory.js +4 -4
  463. package/dist/esm/resources/factories/MusicFactory.js.map +1 -1
  464. package/dist/esm/resources/factories/SoundFactory.d.ts +1 -1
  465. package/dist/esm/resources/factories/SoundFactory.js +3 -3
  466. package/dist/esm/resources/factories/SoundFactory.js.map +1 -1
  467. package/dist/esm/resources/factories/SvgFactory.js +3 -3
  468. package/dist/esm/resources/factories/SvgFactory.js.map +1 -1
  469. package/dist/esm/resources/factories/TextFactory.js +1 -1
  470. package/dist/esm/resources/factories/TextFactory.js.map +1 -1
  471. package/dist/esm/resources/factories/TextureFactory.d.ts +1 -1
  472. package/dist/esm/resources/factories/TextureFactory.js +3 -3
  473. package/dist/esm/resources/factories/TextureFactory.js.map +1 -1
  474. package/dist/esm/resources/factories/VideoFactory.d.ts +2 -2
  475. package/dist/esm/resources/factories/VideoFactory.js +5 -5
  476. package/dist/esm/resources/factories/VideoFactory.js.map +1 -1
  477. package/dist/esm/resources/factories/VttFactory.d.ts +2 -2
  478. package/dist/esm/resources/factories/VttFactory.js +6 -6
  479. package/dist/esm/resources/factories/VttFactory.js.map +1 -1
  480. package/dist/esm/resources/factories/WasmFactory.js.map +1 -1
  481. package/dist/esm/resources/index.d.ts +11 -11
  482. package/dist/esm/resources/utils.js +30 -25
  483. package/dist/esm/resources/utils.js.map +1 -1
  484. package/dist/exo.esm.js +25798 -25144
  485. package/dist/exo.esm.js.map +1 -1
  486. package/package.json +15 -4
package/CHANGELOG.md CHANGED
@@ -4,6 +4,89 @@ 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.2] - 2026-05-09
8
+
9
+ ### Engine
10
+
11
+ - **`Mesh` accepts custom WebGL2 shaders.** New `MeshShaderConfig` + `MeshShaderUniformValue`
12
+ exports. Supply `shader: { vertexSource, fragmentSource, uniforms }` in `MeshOptions` to
13
+ bind a custom GLSL ES 3.00 program against the standard mesh vertex layout. Auto-bound
14
+ uniforms (`u_projection`, `u_translation`, `u_tint`, `u_texture`) are set only when the
15
+ shader declares them, so Shadertoy-style fullscreen passes can ignore them entirely.
16
+ Texture uniforms claim slots 1–7. WebGL2 only in this release; the WebGPU mesh
17
+ renderer throws a clear error pointing to the WebGL2 backend if `mesh.shader` is set.
18
+
19
+ - **Filter chain memory: ping-pong RT reuse.** `RenderNode._renderContentToTexture` now
20
+ releases the previous step's RenderTexture immediately after each `filter.apply`, so
21
+ the pool can hand the same memory back to the next step. Multi-filter chains drop from
22
+ N+1 simultaneously-allocated RTs to a steady-state of 2. ~60% RT-memory reduction on
23
+ 4-filter 1080p chains. Behaviour-identical; no public API change.
24
+
25
+ ### Site / Docs
26
+
27
+ - Part 2 "Core Concepts" guide section published (6 chapters, source-verified):
28
+ Application, Scenes, Scene lifecycle, Scene graph, Coordinates and views,
29
+ Loading and resources.
30
+ - Astro `6.3.0 → 6.3.1`, `@types/node 25.6.0 → 25.6.2` in site/.
31
+
32
+ ### Verification
33
+
34
+ - Engine: 100/100 suites, 1266/1266 tests, lint:strict 0/0, typecheck clean.
35
+ - Site: build green (488 pages), check-ts 0/0, screenshot smoke 36/36.
36
+
37
+ ## [0.8.1] - 2026-05-08
38
+
39
+ Three small additive features that close the remaining examples-driven API gaps from
40
+ the 0.8.0 audit, plus a long-overdue lint/format tooling consolidation and a 19-chapter
41
+ examples reorganisation.
42
+
43
+ ### Added
44
+
45
+ - **`Sound` spatial falloff configuration.** `DistanceModel` type (`'linear' | 'inverse'
46
+ | 'exponential'`), plus optional `distanceModel`, `refDistance`, `maxDistance`, and
47
+ `rolloffFactor` fields on `SoundOptions`. The four are also exposed as live property
48
+ setters that lazy-forward to the attached `PannerNode`. New public `Sound.audioBuffer`
49
+ getter to share one decoded buffer across multiple `Sound` instances.
50
+ - **`LutFilter`** — new colour-pipeline primitive that maps every pixel through a
51
+ Look-Up Table texture. Supports both 1D LUTs (`N×1`, indexed by red channel — palette
52
+ cycling, indexed-colour effects) and 3D LUTs (`N²×N` unwrapped cube with trilinear
53
+ slice interpolation — cinematic colour grading, tone mapping, film stock emulation,
54
+ accessibility filters). Backend selection is automatic. Static helpers
55
+ `LutFilter.identityLut1D(size)`, `LutFilter.identityLut3D(size)`,
56
+ `LutFilter.fromImage(image)` cover the standard DaVinci/OBS/Photoshop LUT-export
57
+ workflows.
58
+ - **`CompressorFilter.reduction`** — public getter forwarding the live gain reduction
59
+ in dB from the underlying `DynamicsCompressorNode`. Use as a meter source for
60
+ visualisations or sidechain triggers.
61
+
62
+ ### Examples
63
+
64
+ - Migrated `examples/public/examples/` to a 19-chapter pedagogical structure: getting
65
+ started, application & scenes, sprites & textures, tweens & animation, input, scene
66
+ graph, audio basics, spatial audio, filters, particles, text & fonts, geometry &
67
+ graphics, render targets, performance, audio FX, beat detection, debug layer, custom
68
+ renderers, showcase. Old chapter directories (`collision-detection`, `extras`,
69
+ `particle-system`, `rendering`, `webgpu`) removed.
70
+ - New examples: `spatial-audio/falloff-curves.js`, `filters/palette-cycling.js`,
71
+ `showcase/color-grading.js`. The compressor demo gained a live gain-reduction meter.
72
+
73
+ ### Tooling
74
+
75
+ - ESLint config consolidated into a single `eslint.config.ts` driven by ESLint 10 +
76
+ `typescript-eslint`'s type-aware checks plus `simple-import-sort`,
77
+ `unused-imports`, `unicorn`, and `security` plugins. `lint:strict` is the
78
+ release-gate variant, scoped to `src/**/*.ts` and run with `--max-warnings=0` (warnings
79
+ fail the build); `lint` is the broader development view across `src`, `test`, and
80
+ examples. Per-subsystem override blocks are documented as known deviations to tighten
81
+ over time.
82
+ - Tightened to error: `eqeqeq`, `no-floating-promises`, `no-base-to-string`,
83
+ `only-throw-error`, `switch-exhaustiveness-check`, `no-non-null-assertion`,
84
+ `complexity` (cap 20). Added: `no-self-compare`, `no-unreachable-loop`,
85
+ `default-case-last`, `prefer-promise-reject-errors`, `no-promise-executor-return`,
86
+ `no-unmodified-loop-condition`, plus six TypeScript and six Unicorn correctness rules.
87
+ - Prettier `printWidth: 160`, `.editorconfig` matched. Engine code reformatted to
88
+ 2-space indent.
89
+
7
90
  ## [0.8.0] - 2026-05-07
8
91
 
9
92
  Wholesale rewrite of the particle subsystem around a data-oriented core
@@ -33,19 +116,19 @@ automatic and per-system; user code is unchanged across both paths.
33
116
  `Uint32Array` / `Uint16Array` channels addressed by slot index:
34
117
 
35
118
  ```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
119
+ system.posX[slot];
120
+ system.posY[slot];
121
+ system.velX[slot];
122
+ system.velY[slot];
123
+ system.scaleX[slot];
124
+ system.scaleY[slot];
125
+ system.rotations[slot];
126
+ system.rotationSpeeds[slot];
127
+ system.color[slot]; // packed 0xAABBGGRR
128
+ system.elapsed[slot];
129
+ system.lifetime[slot];
130
+ system.textureIndex[slot];
131
+ system.liveCount; // [0, liveCount) is the live range
49
132
  ```
50
133
 
51
134
  Capacity is fixed at construction (default 4096) — no reallocations.
@@ -57,17 +140,17 @@ instead of the previous O(n²) splice loop with scattered expirations).
57
140
 
58
141
  Spawn-time random sampling and lifetime-parameterised evaluation:
59
142
 
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 |
143
+ | Type | Use |
144
+ | --------------- | ----------------------------------------------------------------------------- |
145
+ | `Constant<T>` | Always-same value |
146
+ | `Range` | Uniform random number in `[min, max]` |
147
+ | `VectorRange` | Per-axis random vector |
148
+ | `ConeDirection` | Random unit vector in a cone × speed range |
149
+ | `CircleArea` | Random point in/on a circle |
150
+ | `BoxArea` | Random point in/on an AABB |
151
+ | `LineSegment` | Random point on a segment |
152
+ | `Curve` | Piecewise-linear keyframe scalar by lifetime ratio |
153
+ | `Gradient` | Piecewise-linear keyframe color, with `evaluateRgba()` for direct u32 packing |
71
154
 
72
155
  `Curve` and `Gradient` cache the last segment so monotonically
73
156
  advancing `t` (the typical case for per-particle lifetime sampling)
@@ -79,9 +162,15 @@ Three module bases. Each registered on a system via the corresponding
79
162
  `addX` method; each runs in its declared phase per-frame.
80
163
 
81
164
  ```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; }
165
+ abstract class SpawnModule {
166
+ apply(system, dt: number): void;
167
+ }
168
+ abstract class UpdateModule {
169
+ apply(system, dt: number): void;
170
+ }
171
+ abstract class DeathModule {
172
+ onDeath(system, slot: number): void;
173
+ }
85
174
  ```
86
175
 
87
176
  **Built-in spawn modules:**
@@ -121,7 +210,7 @@ for one `ParticleSystem`. At construction time it:
121
210
 
122
211
  1. Walks the registered update modules, collecting each module's
123
212
  `WgslContribution` (uniform field declarations + texture bindings
124
- + WGSL body snippet).
213
+ - WGSL body snippet).
125
214
  2. Generates a composite WGSL compute shader: SoA storage bindings +
126
215
  sim/module uniform structs + module texture bindings + a `main`
127
216
  function containing integration → all module bodies in registration
@@ -151,8 +240,8 @@ Opt-in is a single constructor option — no imperative toggle:
151
240
 
152
241
  ```ts
153
242
  const system = new ParticleSystem(texture, {
154
- capacity: 8192,
155
- backend: app.backend, // CPU-routed on WebGL2, GPU-routed on WebGPU
243
+ capacity: 8192,
244
+ backend: app.backend, // CPU-routed on WebGL2, GPU-routed on WebGPU
156
245
  });
157
246
  ```
158
247
 
@@ -165,25 +254,25 @@ modules after that throws.
165
254
 
166
255
  The following symbols are deleted. Migration recipes follow the table.
167
256
 
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) |
257
+ | Removed | Replacement |
258
+ | -------------------------------------- | ------------------------------------------------------------- |
259
+ | `Particle` (class) | SoA arrays on `ParticleSystem` (`system.posX[slot]`, etc.) |
260
+ | `ParticleProperties` (interface) | None — slot-indexed arrays replace the per-particle object |
261
+ | `ParticleEmitter` (interface) | `SpawnModule` (abstract class) |
262
+ | `ParticleOptions` | Per-property `Distribution<T>` in the spawn module's config |
263
+ | `UniversalEmitter` | `RateSpawn` |
264
+ | `ParticleAffector` (interface) | `UpdateModule` (abstract class) |
265
+ | `ColorAffector` | `ColorOverLifetime` + `Gradient` |
266
+ | `ForceAffector` | `ApplyForce` |
267
+ | `ScaleAffector` | `ScaleOverLifetime` + `Curve` |
268
+ | `TorqueAffector` | `RotateOverLifetime` |
269
+ | `system.requestParticle()` | `system.spawn(): number` (slot index, or `-1` at capacity) |
270
+ | `system.emitParticle(p)` | (gone — `spawn()` already commits the slot to the live range) |
271
+ | `system.updateParticle(p, dt)` | (gone — internal to `update()`) |
272
+ | `system.addEmitter(e)` | `system.addSpawnModule(m)` |
273
+ | `system.addAffector(a)` | `system.addUpdateModule(m)` |
274
+ | `system.particles` (`Array<Particle>`) | `system.posX` / `system.posY` / ... `system.liveCount` |
275
+ | `system.graveyard` | (gone — no graveyard; slots are recycled in place) |
187
276
 
188
277
  ### Migration
189
278
 
@@ -203,16 +292,22 @@ options.velocity.set(/* ... */);
203
292
 
204
293
  // After — bonfire
205
294
  const system = new ParticleSystem(texture);
206
- system.addSpawnModule(new RateSpawn({
295
+ system.addSpawnModule(
296
+ new RateSpawn({
207
297
  rate: new Constant(50),
208
298
  lifetime: new Range(5, 10),
209
299
  position: new VectorRange(-50, 50, -10, 10),
210
300
  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
- ])));
301
+ }),
302
+ );
303
+ system.addUpdateModule(
304
+ new ColorOverLifetime(
305
+ new Gradient([
306
+ { t: 0, color: new Color(194, 64, 30, 1) },
307
+ { t: 1, color: new Color(0, 0, 0, 0) },
308
+ ]),
309
+ ),
310
+ );
216
311
  // no per-frame mutation needed.
217
312
  ```
218
313
 
@@ -228,23 +323,23 @@ system.addUpdateModule(new ApplyForce(0, 980));
228
323
  ```ts
229
324
  // Before — custom affector
230
325
  class AlphaFade {
231
- apply(particle, delta) {
232
- particle.tint.a = particle.remainingRatio;
233
- return this;
234
- }
235
- destroy() {}
326
+ apply(particle, delta) {
327
+ particle.tint.a = particle.remainingRatio;
328
+ return this;
329
+ }
330
+ destroy() {}
236
331
  }
237
332
 
238
333
  // After
239
334
  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
- }
335
+ apply(system) {
336
+ const { color, elapsed, lifetime, liveCount } = system;
337
+ for (let i = 0; i < liveCount; i++) {
338
+ const remaining = 1 - elapsed[i] / lifetime[i];
339
+ const a = (Math.max(0, Math.min(1, remaining)) * 255) & 255;
340
+ color[i] = (color[i] & 0x00ffffff) | (a << 24);
247
341
  }
342
+ }
248
343
  }
249
344
  ```
250
345
 
@@ -279,12 +374,12 @@ new ParticleSystem(texture);
279
374
  new ParticleSystem(texture, 4096);
280
375
 
281
376
  // 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
377
+ new ParticleSystem(); // untextured (1×1 white), CPU/GPU auto-routed
378
+ new ParticleSystem(spark); // simple textured particles
379
+ new ParticleSystem(spark, { capacity: 8192 }); // explicit capacity
380
+ new ParticleSystem(atlas, [r0, r1, r2]); // multi-frame atlas
286
381
  new ParticleSystem(atlas, frames, { capacity: 8192 }); // atlas + capacity
287
- new ParticleSystem(sheet); // spritesheet shorthand
382
+ new ParticleSystem(sheet); // spritesheet shorthand
288
383
  new ParticleSystem(sheet, { capacity: 4096 });
289
384
  ```
290
385
 
@@ -300,9 +395,9 @@ constructor(spritesheet: Spritesheet, options?: ParticleSystemOptions);
300
395
  Compile-time errors for illegal combinations:
301
396
 
302
397
  ```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
398
+ new ParticleSystem(spark, sheet); // ✗ no overload matches
399
+ new ParticleSystem(sheet, frames); // ✗ frames only valid with Texture
400
+ new ParticleSystem({ frames }); // ✗ frames isn't an option
306
401
  ```
307
402
 
308
403
  **No `backend` option** — the renderer auto-discovers the active backend
@@ -326,19 +421,21 @@ frame chooser:
326
421
 
327
422
  ```ts
328
423
  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
- ],
424
+ texture: explosionAtlas,
425
+ frames: [
426
+ new Rectangle(0, 0, 32, 32), // index 0 — flame core
427
+ new Rectangle(32, 0, 32, 32), // index 1 — smoke ring
428
+ new Rectangle(64, 0, 32, 32), // index 2 — ember
429
+ ],
335
430
  });
336
431
 
337
- system.addSpawnModule(new BurstSpawn({
432
+ system.addSpawnModule(
433
+ new BurstSpawn({
338
434
  schedule: [{ time: 0, count: 60 }],
339
435
  velocity: ConeDirection.omni(120, 280),
340
- textureIndex: new Range(0, 2), // each spawn picks a random frame
341
- }));
436
+ textureIndex: new Range(0, 2), // each spawn picks a random frame
437
+ }),
438
+ );
342
439
  ```
343
440
 
344
441
  `Spritesheet` integration via `spritesheet: sheet` extracts texture +
@@ -373,6 +470,7 @@ update). `spawn()` always returns the next sequential slot.
373
470
 
374
471
  In GPU mode, no compaction happens — readback would be required to
375
472
  move slots whose authoritative position lives in GPU memory. Instead:
473
+
376
474
  - Each particle has an `alive: Uint8Array` flag (1 = alive, 0 = dead).
377
475
  - `spawn()` finds the first dead slot via a round-robin hint pointer
378
476
  (amortised O(1), worst case O(capacity)).
@@ -422,7 +520,7 @@ signed stick channels, and Joy-Con-honest mappings.
422
520
  ```ts
423
521
  // Per inputManager (manual unbind):
424
522
  app.input.onTrigger(GamepadButton.South, () => player.jump());
425
- app.input.onActive(GamepadAxis.LeftStickX, (v) => player.x += v * 5);
523
+ app.input.onActive(GamepadAxis.LeftStickX, v => (player.x += v * 5));
426
524
  app.input.onStart([Keyboard.Space, GamepadButton.South], () => fire());
427
525
 
428
526
  // Per gamepad (slot-aware, listener survives disconnect/reconnect):
@@ -466,8 +564,8 @@ default `'sticky'` (each pad keeps its slot through disconnects).
466
564
  disconnect (good for hot-seat couch coop where "the first N pads are
467
565
  the N players" is the desired semantic).
468
566
 
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
567
+ In compact mode, the disconnect signal fires on the slot that _ended
568
+ up_ empty after the shift (not the slot the disconnected hardware
471
569
  originally occupied), keeping `pad.connected === false` consistent with
472
570
  the fired event. Slots that received a different physical pad through
473
571
  the shift dispatch a separate signal:
@@ -481,6 +579,7 @@ player when slots renumber.
481
579
  ### Added — Generic signals
482
580
 
483
581
  Per-pad:
582
+
484
583
  - `pad.onConnect: Signal<[]>`
485
584
  - `pad.onDisconnect: Signal<[]>`
486
585
  - `pad.onButtonDown: Signal<[GamepadButton, number]>`
@@ -488,6 +587,7 @@ Per-pad:
488
587
  - `pad.onAxisChange: Signal<[GamepadAxis, number]>`
489
588
 
490
589
  Aggregate across all pads:
590
+
491
591
  - `inputManager.onAnyGamepadButtonDown: Signal<[Gamepad, GamepadButton, number]>`
492
592
  - `inputManager.onAnyGamepadButtonUp: Signal<[Gamepad, GamepadButton, number]>`
493
593
  - `inputManager.onAnyGamepadAxisChange: Signal<[Gamepad, GamepadAxis, number]>`
@@ -496,7 +596,7 @@ Aggregate across all pads:
496
596
 
497
597
  ```ts
498
598
  if (pad.canVibrate) {
499
- await pad.vibrate({ duration: 200, weakMagnitude: 0.5, strongMagnitude: 1.0 });
599
+ await pad.vibrate({ duration: 200, weakMagnitude: 0.5, strongMagnitude: 1.0 });
500
600
  }
501
601
  pad.stopVibration();
502
602
  ```
@@ -517,18 +617,18 @@ remain available for buttons-style 0..1 input.
517
617
 
518
618
  ```ts
519
619
  // Stick-style — one binding per axis, signed value:
520
- this.inputs.onActive(GamepadAxis.LeftStickX, (x) => player.x += x * 5);
620
+ this.inputs.onActive(GamepadAxis.LeftStickX, x => (player.x += x * 5));
521
621
 
522
622
  // 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);
623
+ this.inputs.onActive(GamepadAxis.LeftStickLeft, v => (player.x -= v * 5));
624
+ this.inputs.onActive(GamepadAxis.LeftStickRight, v => (player.x += v * 5));
525
625
  ```
526
626
 
527
627
  ### Added — `pad.hasChannel(channel)` capability check
528
628
 
529
629
  ```ts
530
630
  if (pad.hasChannel(GamepadAxis.RightStickX)) {
531
- pad.onActive(GamepadAxis.RightStickX, (v) => crosshair.x += v * 8);
631
+ pad.onActive(GamepadAxis.RightStickX, v => (crosshair.x += v * 8));
532
632
  }
533
633
  ```
534
634
 
@@ -545,19 +645,19 @@ Internally tracks each binding and calls `.unbind()` in `Scene.destroy`.
545
645
  ### Added — Steam Deck / Steam Virtual Gamepad / Valve fallback
546
646
 
547
647
  New `SteamDeckGamepadMapping` covers the raw HID layout reported by the
548
- Steam Deck (and likely future Valve hardware) when Steam Input is *not*
648
+ Steam Deck (and likely future Valve hardware) when Steam Input is _not_
549
649
  intercepting the device. Indices follow the SDL_GameControllerDB Linux
550
650
  entry: face buttons at 3-6, D-pad at 16-19, paddles at 20-23, triggers
551
651
  as analog axes 8/9.
552
652
 
553
653
  Routing rules added to `builtInGamepadDefinitions`:
554
654
 
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) |
655
+ | Browser ID | Mapping |
656
+ | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
657
+ | `28de:1102`, `28de:1142` | `SteamControllerGamepadMapping` (existing, original Steam Controller raw) |
658
+ | `28de:11ff` (Steam Virtual Gamepad — any controller via Steam Input) | `GenericDualAnalogGamepadMapping` (W3C standard Xbox emulation) |
659
+ | `28de:1205` | `SteamDeckGamepadMapping` (raw Steam Deck) |
660
+ | Vendor `28de` (anything else from Valve, e.g. future Steam Controller 2 raw) | `SteamDeckGamepadMapping` (best-effort fallback) |
561
661
 
562
662
  Enum: `GamepadMappingFamily.SteamDeck` added.
563
663
 
@@ -610,7 +710,7 @@ app.input.getGamepad(0);
610
710
  ### Fixed — Compact-mode disconnect ordering
611
711
 
612
712
  In `'compact'` slot strategy, `onDisconnect` previously fired on the
613
- slot the disconnected hardware originally occupied — *before* the
713
+ slot the disconnected hardware originally occupied — _before_ the
614
714
  compaction shift moved a different physical pad into that slot. User
615
715
  code observing the event would see `pad.connected === true` because
616
716
  the slot had been silently re-bound by the shift. Now compaction is
@@ -622,13 +722,13 @@ ended up empty (the trailing slot). Sticky behaviour is unchanged.
622
722
  The unified `GamepadChannel` enum is split into two disjoint enums for
623
723
  nominal type safety:
624
724
 
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
- | ... | ... | ... |
725
+ | Old | New (user-facing) | New (internal type) |
726
+ | ------------------------------ | ---------------------------- | ----------------------------------- |
727
+ | `GamepadChannel.ButtonSouth` | `GamepadButton.South` | `GamepadButtonChannel.South` |
728
+ | `GamepadChannel.ButtonEast` | `GamepadButton.East` | `GamepadButtonChannel.East` |
729
+ | `GamepadChannel.LeftShoulder` | `GamepadButton.LeftShoulder` | `GamepadButtonChannel.LeftShoulder` |
730
+ | `GamepadChannel.LeftStickLeft` | `GamepadAxis.LeftStickLeft` | `GamepadAxisChannel.LeftStickLeft` |
731
+ | ... | ... | ... |
632
732
 
633
733
  User code references the namespace mirrors (`GamepadButton.X`,
634
734
  `GamepadAxis.Y`) — same `Pointer.X` / `Keyboard.Space` convention. Type
@@ -670,11 +770,11 @@ instead of firing every frame.
670
770
 
671
771
  ```ts
672
772
  // Before:
673
- new Gamepad(index, channels, mapping)
674
- new Gamepad(browserGamepad, channels, definition)
773
+ new Gamepad(index, channels, mapping);
774
+ new Gamepad(browserGamepad, channels, definition);
675
775
 
676
776
  // After (engine-internal — InputManager handles slot allocation):
677
- new Gamepad(slot, channels)
777
+ new Gamepad(slot, channels);
678
778
  // followed by pad._bind(browserGamepad, definition) on connect
679
779
  ```
680
780
 
@@ -696,7 +796,7 @@ import { GamepadButton, Keyboard } from '@codexo/exojs';
696
796
 
697
797
  // Manual lifecycle
698
798
  const binding = app.input.onTrigger(GamepadButton.South, () => player.jump());
699
- binding.unbind(); // when done
799
+ binding.unbind(); // when done
700
800
 
701
801
  // Auto-disposed on scene unload
702
802
  this.inputs.onTrigger(GamepadButton.South, () => player.jump());
@@ -707,37 +807,31 @@ this.app.input.gamepads[0].onTrigger(GamepadButton.South, () => player.jump());
707
807
 
708
808
  ```ts
709
809
  // Stick movement — before:
710
- const moveLeft = new Input(GamepadChannel.LeftStickLeft);
810
+ const moveLeft = new Input(GamepadChannel.LeftStickLeft);
711
811
  const moveRight = new Input(GamepadChannel.LeftStickRight);
712
812
  app.input.add(moveLeft);
713
813
  app.input.add(moveRight);
714
814
  // per frame: const x = moveRight.value - moveLeft.value;
715
815
 
716
816
  // After (signed aggregate channel):
717
- this.inputs.onActive(GamepadAxis.LeftStickX, (x) => player.x += x * 5);
817
+ this.inputs.onActive(GamepadAxis.LeftStickX, x => (player.x += x * 5));
718
818
  ```
719
819
 
720
820
  ```ts
721
821
  // Custom mapping — before:
722
822
  import { GamepadMapping, GamepadChannel } from '@codexo/exojs';
723
823
  const buttons = GamepadMapping.createControls([
724
- [0, GamepadChannel.ButtonSouth],
725
- [1, GamepadChannel.ButtonEast],
824
+ [0, GamepadChannel.ButtonSouth],
825
+ [1, GamepadChannel.ButtonEast],
726
826
  ]);
727
827
 
728
828
  // After:
729
829
  import { GamepadButton, GamepadMapping, GamepadMappingFamily } from '@codexo/exojs';
730
830
  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
- }
831
+ public readonly family = GamepadMappingFamily.GenericDualAnalog;
832
+ public constructor() {
833
+ super([new GamepadButton(0, GamepadButton.South), new GamepadButton(1, GamepadButton.East)], []);
834
+ }
741
835
  }
742
836
  ```
743
837
 
@@ -863,7 +957,7 @@ indexing is now automatic and persistent).
863
957
  audio, collision, scene-graph, interaction. Each domain has its own
864
958
  script (`npm run perf:bench:rendering`, `:audio`, `:collision`,
865
959
  `:scene-graph`, `:interaction`) plus `:all` aggregator. Output: JSON
866
- + Markdown to `test/perf/results/`.
960
+ - Markdown to `test/perf/results/`.
867
961
  - **Baseline snapshot** committed as `test/perf/results/baseline.md` —
868
962
  reference numbers at 0.7.10 for future regression detection.
869
963
  - **Auto-profiler** (`npm run perf:profile`, `:gc` variant with
@@ -903,6 +997,7 @@ also makes the `useSpatialIndex` opt-in flag unnecessary and **the
903
997
  flag has been removed entirely**.
904
998
 
905
999
  **How it works now:**
1000
+
906
1001
  - A persistent quadtree is created lazily when the first interactive
907
1002
  node enters the scene.
908
1003
  - `Container.addChild` / `removeChild` walk subtrees and add/remove
@@ -943,7 +1038,7 @@ actually-moved nodes.
943
1038
 
944
1039
  ```ts
945
1040
  // Before:
946
- app.interaction.useSpatialIndex = true; // flag opt-in
1041
+ app.interaction.useSpatialIndex = true; // flag opt-in
947
1042
 
948
1043
  // After:
949
1044
  // Nothing — index is automatic. Just have at least one interactive
@@ -1046,7 +1141,7 @@ Fixes a GLSL compile-error in the 0.7.8 shader auto-upgrade path.
1046
1141
  ### Fixed
1047
1142
 
1048
1143
  - **`upgradeFragmentShaderToGl300()` now always prepends `precision highp
1049
- float;`** before the `out vec4 fragColor;` declaration. Previously, if
1144
+ float;`** before the `out vec4 fragColor;` declaration. Previously, if
1050
1145
  the user's source already contained a precision declaration anywhere
1051
1146
  (e.g., `precision lowp float;` mid-source), the upgrader skipped its
1052
1147
  own injection — but the user's declaration came AFTER the
@@ -1057,7 +1152,7 @@ Fixes a GLSL compile-error in the 0.7.8 shader auto-upgrade path.
1057
1152
 
1058
1153
  Multiple precision declarations are legal in GLSL ES 3.00 with
1059
1154
  last-precision-wins semantics. The fix always injects `precision highp
1060
- float;` at line 2 (before `out vec4 fragColor;`); the user's own
1155
+ float;` at line 2 (before `out vec4 fragColor;`); the user's own
1061
1156
  precision declaration further down still applies to their code via
1062
1157
  the standard last-precision-wins rule. No semantic change for
1063
1158
  user-provided shader logic; previously-broken shaders with custom
@@ -1256,7 +1351,7 @@ app.backend.setCursor('pointer');
1256
1351
  const cursor = app.backend.cursor;
1257
1352
 
1258
1353
  // After:
1259
- app.setCursor('pointer'); // or
1354
+ app.setCursor('pointer'); // or
1260
1355
  app.cursor = 'pointer';
1261
1356
  const cursor = app.cursor;
1262
1357
  ```
@@ -1264,14 +1359,14 @@ const cursor = app.cursor;
1264
1359
  ```ts
1265
1360
  // New: react to backend loss
1266
1361
  app.onBackendLost.add(() => {
1267
- showReloadDialog();
1362
+ showReloadDialog();
1268
1363
  });
1269
1364
 
1270
1365
  // Or backend-specific:
1271
1366
  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
- });
1367
+ (app.backend as WebGpuBackend).onDeviceLost.add(info => {
1368
+ console.error('GPU device lost:', info.message, info.reason);
1369
+ });
1275
1370
  }
1276
1371
  ```
1277
1372
 
@@ -1380,9 +1475,9 @@ etc.).
1380
1475
  separate `WebGpuShaderFilter`.
1381
1476
  - **Backend guard messages updated**:
1382
1477
  - `WebGl2ShaderFilter` on WebGPU: `'WebGl2ShaderFilter requires the
1383
- WebGL2 backend. Use WebGpuShaderFilter on WebGPU.'`
1478
+ WebGL2 backend. Use WebGpuShaderFilter on WebGPU.'`
1384
1479
  - `WebGpuShaderFilter` on WebGL2: `'WebGpuShaderFilter requires the
1385
- WebGPU backend. Use WebGl2ShaderFilter on WebGL2.'`
1480
+ WebGPU backend. Use WebGl2ShaderFilter on WebGL2.'`
1386
1481
 
1387
1482
  `ShaderFilterUniformValue` (the polymorphic uniform value type) is
1388
1483
  **unchanged** and shared between both backends — same value shapes
@@ -1443,7 +1538,7 @@ LUT color grading, chromatic aberration, etc.
1443
1538
  via property assignment; flushed before each apply():
1444
1539
  ```ts
1445
1540
  filter.uniforms.uTime = performance.now() / 1000;
1446
- filter.uniforms.uColor = [1, 0.5, 0, 1]; // vec4
1541
+ filter.uniforms.uColor = [1, 0.5, 0, 1]; // vec4
1447
1542
  ```
1448
1543
  - **Polymorphic uniform values**: scalar `number`, tuple `[a, b]` /
1449
1544
  `[a, b, c]` / `[a, b, c, d]`, `Float32Array` / `Int32Array`, or
@@ -1458,8 +1553,8 @@ LUT color grading, chromatic aberration, etc.
1458
1553
 
1459
1554
  - **WebGL2-only in V1.** Constructor accepts `wgsl` source, but `apply()`
1460
1555
  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
1556
+ WebGPU backend. WGSL support is planned for a future release. Use the
1557
+ WebGL2 backend for now.'` Document this limitation; reasoning: WebGPU
1463
1558
  requires a separate WGSL pipeline implementation that's substantial
1464
1559
  on its own. Coming when there's concrete user demand.
1465
1560
  - `fragmentSource` is required at construction. Constructor throws if
@@ -1476,7 +1571,7 @@ LUT color grading, chromatic aberration, etc.
1476
1571
  import { ShaderFilter } from '@codexo/exojs';
1477
1572
 
1478
1573
  const filter = new ShaderFilter({
1479
- fragmentSource: `#version 300 es
1574
+ fragmentSource: `#version 300 es
1480
1575
  precision highp float;
1481
1576
  in vec2 vUv;
1482
1577
  uniform sampler2D uTexture;
@@ -1489,15 +1584,15 @@ const filter = new ShaderFilter({
1489
1584
  outColor = texture(uTexture, uv);
1490
1585
  }
1491
1586
  `,
1492
- uniforms: {
1493
- uTime: 0,
1494
- },
1587
+ uniforms: {
1588
+ uTime: 0,
1589
+ },
1495
1590
  });
1496
1591
 
1497
1592
  sprite.filters = [filter];
1498
1593
 
1499
- app.onFrame.add((delta) => {
1500
- filter.uniforms.uTime = performance.now() / 1000;
1594
+ app.onFrame.add(delta => {
1595
+ filter.uniforms.uTime = performance.now() / 1000;
1501
1596
  });
1502
1597
  ```
1503
1598
 
@@ -1583,10 +1678,10 @@ const spectrum = analyser.getSpectrum();
1583
1678
  const waveform = analyser.getWaveform();
1584
1679
 
1585
1680
  // Now also possible:
1586
- analyser.source = mediaStream; // Mic input
1681
+ analyser.source = mediaStream; // Mic input
1587
1682
  analyser.source = app.audio.master; // Whole mix
1588
- analyser.getBandEnergy(20, 200); // Bass energy 0..1
1589
- analyser.getLowMidHigh(); // {low, mid, high}
1683
+ analyser.getBandEnergy(20, 200); // Bass energy 0..1
1684
+ analyser.getLowMidHigh(); // {low, mid, high}
1590
1685
  ```
1591
1686
 
1592
1687
  ```ts
@@ -1596,12 +1691,12 @@ detector.source = music;
1596
1691
  await detector.ready;
1597
1692
 
1598
1693
  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();
1694
+ sprite.scale.set(1.5);
1695
+ new Tween().target(sprite.scale).to({ x: 1, y: 1 }).duration(200).start();
1601
1696
  });
1602
1697
 
1603
1698
  detector.onDownbeat.add(() => {
1604
- boss.attack(); // syncs exactly to "the 1" of each bar
1699
+ boss.attack(); // syncs exactly to "the 1" of each bar
1605
1700
  });
1606
1701
  ```
1607
1702
 
@@ -1770,22 +1865,22 @@ breaking change.
1770
1865
 
1771
1866
  ```ts
1772
1867
  // Before:
1773
- sound.play(); // singleton — second call replaces first
1774
- sound.playPooled(); // multi-instance — concurrent plays
1868
+ sound.play(); // singleton — second call replaces first
1869
+ sound.playPooled(); // multi-instance — concurrent plays
1775
1870
 
1776
1871
  // After:
1777
- sound.play(); // multi-instance — concurrent plays (default!)
1872
+ sound.play(); // multi-instance — concurrent plays (default!)
1778
1873
  sound.play({ replace: true }); // singleton — equivalent of old play()
1779
1874
  ```
1780
1875
 
1781
1876
  ```ts
1782
1877
  // Before — direct destination routing was implicit:
1783
1878
  const sound = new Sound(buffer);
1784
- sound.play(); // → audioContext.destination
1879
+ sound.play(); // → audioContext.destination
1785
1880
 
1786
1881
  // After — routes through the soundBus by default:
1787
1882
  const sound = new Sound(buffer);
1788
- sound.play(); // → app.audio.sound → app.audio.master → destination
1883
+ sound.play(); // → app.audio.sound → app.audio.master → destination
1789
1884
 
1790
1885
  // Override to a custom bus:
1791
1886
  const dialogueBus = new AudioBus('dialogue', { parent: app.audio.master });
@@ -1796,8 +1891,8 @@ sound.bus = dialogueBus;
1796
1891
  ```ts
1797
1892
  // Spatial audio:
1798
1893
  const explosion = new Sound(buffer);
1799
- explosion.position = { x: 200, y: 100 }; // becomes spatial
1800
- app.audio.listener.target = playerSprite; // ears follow player
1894
+ explosion.position = { x: 200, y: 100 }; // becomes spatial
1895
+ app.audio.listener.target = playerSprite; // ears follow player
1801
1896
 
1802
1897
  explosion.play();
1803
1898
  // → routes through equalpower panner with distance falloff
@@ -1834,7 +1929,7 @@ infrastructure. Pure additive — no behavior changes for existing code.
1834
1929
  **world-space position** via `getGlobalTransform()`, so following a
1835
1930
  Sprite nested under a translated/rotated Container works correctly.
1836
1931
  New exported type `ViewFollowTarget = SceneNode | { x: number; y:
1837
- number } | null`.
1932
+ number } | null`.
1838
1933
  - **Audio fade helpers on `AbstractMedia`** — both `Sound` and `Music`
1839
1934
  inherit:
1840
1935
  - `fadeIn(durationMs): this` — ramps gain from 0 to current volume.
@@ -1901,7 +1996,7 @@ detection. Pure performance change — no public API surface changes.
1901
1996
  components. Recomputes only when the sprite's transform or local
1902
1997
  bounds change. Previously had a `// todo cache this` comment.
1903
1998
  - **`Sprite.getNormals()`** returns a stable `[Vector, Vector,
1904
- Vector, Vector]` array. The four `Vector` instances are reused
1999
+ Vector, Vector]` array. The four `Vector` instances are reused
1905
2000
  across calls; previously each call allocated four new `Vector`s.
1906
2001
  Recomputes only when vertices change. Reduces GC pressure in
1907
2002
  collision-detection hot paths.
@@ -1983,7 +2078,7 @@ per-frame application hook.
1983
2078
 
1984
2079
  - **`Application.debug` removed** — was added in 0.6.15. Apps that
1985
2080
  used `app.debug.show()` must migrate to `import { DebugOverlay }
1986
- from '@codexo/exojs/debug'` and instantiate manually. **Breaking
2081
+ from '@codexo/exojs/debug'` and instantiate manually. **Breaking
1987
2082
  change**, but the affected window is one day (0.6.15 → 0.6.17).
1988
2083
 
1989
2084
  ### Notes
@@ -2080,7 +2175,7 @@ zero cost when not shown.
2080
2175
 
2081
2176
  Reshapes the interaction system around a per-frame tick and adds an
2082
2177
  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.
2178
+ is unchanged; only event _cadence_ and a new `draggable` flag.
2084
2179
 
2085
2180
  ### Added
2086
2181
 
@@ -2216,12 +2311,13 @@ existing surface changes shape.
2216
2311
  properties on any target object:
2217
2312
 
2218
2313
  ```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();
2314
+ app.tweens
2315
+ .create(sprite)
2316
+ .to({ x: 100, alpha: 0.5 }, 1.0) // 1 second
2317
+ .easing(Ease.cubicOut)
2318
+ .delay(0.2)
2319
+ .onComplete(() => console.log('done'))
2320
+ .start();
2225
2321
  ```
2226
2322
 
2227
2323
  Lifecycle: `Idle → Active → Complete | Stopped` (with
@@ -2233,6 +2329,7 @@ existing surface changes shape.
2233
2329
  interpolation), `onUpdate` (per frame), `onRepeat` (cycle
2234
2330
  boundaries), `onComplete` (final cycle ends naturally).
2235
2331
  `stop()` does NOT fire `onComplete`.
2332
+
2236
2333
  - **`TweenManager` class.** Owns active tweens and ticks them
2237
2334
  from `Application.update()`. Use `app.tweens.create(target)` to
2238
2335
  spawn-and-register a tween in one call; `app.tweens.add(tween)`
@@ -2328,7 +2425,7 @@ one atlas — memory-efficient at scale, single drawcall per Text.
2328
2425
 
2329
2426
  - **`DynamicGlyphAtlas`** — public class. Constructor takes
2330
2427
  `width = 1024, height = 1024`. Has `getGlyph(char, family, size,
2331
- weight, style) → GlyphInfo` (cached or rasterizes), `clear()` to
2428
+ weight, style) → GlyphInfo` (cached or rasterizes), `clear()` to
2332
2429
  reset, and `texture` for binding to a Mesh. Internal shelf
2333
2430
  bin-packing; throws on atlas-full (LRU eviction is V2).
2334
2431
  - **`layoutText(text, style, atlas)`** — pure function. Returns
@@ -2340,7 +2437,7 @@ one atlas — memory-efficient at scale, single drawcall per Text.
2340
2437
  their own atlas / layout pipelines.
2341
2438
  - **TextStyle gets `fillColor: Color`** (defaults to white, used
2342
2439
  via mesh.tint after glyph rasterization), **`fontStyle: 'normal'
2343
- | 'italic'`**, and **`lineHeight: number`** (multiplied by
2440
+ | 'italic'`**, and **`lineHeight: number`** (multiplied by
2344
2441
  fontSize for line spacing, defaults to 1.2). `align` field is
2345
2442
  now strongly typed as `TextAlignment`.
2346
2443
 
@@ -2370,8 +2467,8 @@ one atlas — memory-efficient at scale, single drawcall per Text.
2370
2467
  `document.createElement('canvas')` (works in jsdom / older
2371
2468
  browsers).
2372
2469
  - 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.
2470
+ - texture re-upload. Cached glyphs are zero-cost on subsequent
2471
+ renders.
2375
2472
  - Per-character animation, MSDF rendering, word-wrap, BiDi, and
2376
2473
  text outlines / drop-shadows are all V2.
2377
2474
 
@@ -2540,7 +2637,7 @@ one unified rendering path for everything triangle-shaped.
2540
2637
  (`buildLine`, `buildPath`, `buildCircle`, `buildEllipse`,
2541
2638
  `buildRectangle`, `buildPolygon`, `buildStar`) now return a
2542
2639
  `MeshGeometryData` plain object — `{ vertices: Float32Array,
2543
- indices: Uint16Array, points: Array<number> }` — directly suitable
2640
+ indices: Uint16Array, points: Array<number> }` — directly suitable
2544
2641
  for `new Mesh({ ... })`.
2545
2642
  - **`WebGl2PrimitiveRenderer` and `WebGpuPrimitiveRenderer` removed.**
2546
2643
  Their work moved entirely into the existing `*MeshRenderer`s. Both
@@ -2569,18 +2666,14 @@ one unified rendering path for everything triangle-shaped.
2569
2666
  // Before (0.6.4)
2570
2667
  import { DrawableShape, Geometry, RenderingPrimitives, Color } from '@codexo/exojs';
2571
2668
 
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
- );
2669
+ const shape = new DrawableShape(new Geometry({ vertices: [0, 0, 100, 0, 50, 100], indices: [0, 1, 2] }), Color.red, RenderingPrimitives.Triangles);
2577
2670
 
2578
2671
  // After (0.6.5)
2579
2672
  import { Mesh, Color } from '@codexo/exojs';
2580
2673
 
2581
2674
  const mesh = new Mesh({
2582
- vertices: new Float32Array([0, 0, 100, 0, 50, 100]),
2583
- indices: new Uint16Array([0, 1, 2]),
2675
+ vertices: new Float32Array([0, 0, 100, 0, 50, 100]),
2676
+ indices: new Uint16Array([0, 1, 2]),
2584
2677
  });
2585
2678
  mesh.tint = Color.red;
2586
2679
  ```
@@ -2656,13 +2749,13 @@ match the rest of ExoJS.
2656
2749
  ```ts
2657
2750
  // Before (0.6.3)
2658
2751
  import { capabilities, isSupported } from '@codexo/exojs';
2659
- if (capabilities.webgpu) startWebGpu(); // false positives possible
2752
+ if (capabilities.webgpu) startWebGpu(); // false positives possible
2660
2753
  if (isSupported('touch')) showTouchUi();
2661
2754
 
2662
2755
  // After (0.6.4)
2663
2756
  import { Capabilities } from '@codexo/exojs';
2664
2757
  const caps = await Capabilities.ready;
2665
- if (caps.webgpuAdapter) startWebGpu(); // strict adapter check
2758
+ if (caps.webgpuAdapter) startWebGpu(); // strict adapter check
2666
2759
  if (caps.touch) showTouchUi();
2667
2760
 
2668
2761
  // Or via Application after start:
@@ -2782,12 +2875,12 @@ and breaks freely between minors.
2782
2875
  - **`Scene` is class-only; the plain-object definition constructor is
2783
2876
  gone.** `new Scene({ update() { ... } })` no longer works. Subclass
2784
2877
  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
2878
+ update(...) { ... } }` for named scenes, `new class extends Scene
2879
+ { ... }` for one-offs. The `SceneData` interface and
2787
2880
  `SceneInstance<T>` type alias are removed (they only existed to
2788
2881
  type the spread-into-`this` constructor). Internal Scene fields
2789
2882
  move from ECMAScript `#`-private to TS `protected _app/_root/
2790
- _stackMode/_inputMode` — subclasses can now reach internal state
2883
+ _stackMode/_inputMode` — subclasses can now reach internal state
2791
2884
  directly when they need to.
2792
2885
  - **npm package shape simplified.** Dropped: `dist/exo.global.js` /
2793
2886
  `dist/exo.global.min.js` (legacy IIFE for `<script>` use) and
@@ -2848,33 +2941,49 @@ and breaks freely between minors.
2848
2941
  ```ts
2849
2942
  // Before (0.5.x)
2850
2943
  class GameScene extends Scene {
2851
- override draw(runtime: SceneRenderRuntime): void {
2852
- this.root.render(runtime);
2853
- }
2944
+ override draw(runtime: SceneRenderRuntime): void {
2945
+ this.root.render(runtime);
2946
+ }
2854
2947
  }
2855
2948
 
2856
2949
  const triangleRenderer = new CustomRenderer(app.renderManager);
2857
2950
 
2858
- if (app.renderManager instanceof WebGpuRenderManager) { /* ... */ }
2951
+ if (app.renderManager instanceof WebGpuRenderManager) {
2952
+ /* ... */
2953
+ }
2859
2954
 
2860
2955
  // Plain-object scene
2861
- app.start(new Scene({ update() { /* ... */ } }));
2956
+ app.start(
2957
+ new Scene({
2958
+ update() {
2959
+ /* ... */
2960
+ },
2961
+ }),
2962
+ );
2862
2963
  ```
2863
2964
 
2864
2965
  ```ts
2865
2966
  // After (0.6.0)
2866
2967
  class GameScene extends Scene {
2867
- override draw(backend: RenderBackend): void {
2868
- this.root.render(backend);
2869
- }
2968
+ override draw(backend: RenderBackend): void {
2969
+ this.root.render(backend);
2970
+ }
2870
2971
  }
2871
2972
 
2872
2973
  const triangleRenderer = new CustomRenderer(app.backend);
2873
2974
 
2874
- if (app.backend instanceof WebGpuBackend) { /* ... */ }
2975
+ if (app.backend instanceof WebGpuBackend) {
2976
+ /* ... */
2977
+ }
2875
2978
 
2876
2979
  // Anonymous-subclass scene (or named subclass)
2877
- app.start(new class extends Scene { override update() { /* ... */ } });
2980
+ app.start(
2981
+ new (class extends Scene {
2982
+ override update() {
2983
+ /* ... */
2984
+ }
2985
+ })(),
2986
+ );
2878
2987
  ```
2879
2988
 
2880
2989
  ## [0.5.1] - 2026-04-28
@@ -2968,6 +3077,7 @@ Three focused breaking changes targeted at the first pre-1.0 minor: a hierarchy-
2968
3077
  - `null` — no mask.
2969
3078
 
2970
3079
  Setting `node.mask = node` (self-mask) throws at runtime.
3080
+
2971
3081
  - **`SceneRenderRuntime` mask primitives renamed** to match the new vocabulary:
2972
3082
  - `pushMask(maskBounds)` / `popMask()` → `pushScissorRect(bounds)` / `popScissorRect()` (lower-level scissor primitive used internally by the `Rectangle` mask path).
2973
3083
  - New `composeWithAlphaMask(content, mask, x, y, width, height, blendMode)` — used internally by the Texture/RenderTexture/RenderNode mask paths.
@@ -2985,19 +3095,19 @@ Three focused breaking changes targeted at the first pre-1.0 minor: a hierarchy-
2985
3095
 
2986
3096
  ### Migration
2987
3097
 
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()` |
3098
+ | Before (0.4.x) | After |
3099
+ | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
3100
+ | `import { Transformable } from '@codexo/exojs'`; `class X extends Transformable` | `import { SceneNode } from '@codexo/exojs'`; `class X extends SceneNode` |
3101
+ | `import { TransformableFlags } from '@codexo/exojs'` | Internal flag enum is no longer public; use SceneNode's high-level transform accessors instead. |
3102
+ | `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)_ |
3103
+ | Want fast axis-aligned clipping? | `node.mask = new Rectangle(x, y, w, h)` |
3104
+ | Want to clip with a texture's alpha channel? | `node.mask = texture` or `node.mask = renderTexture` |
3105
+ | Want a transformed/positioned alpha mask? | `node.mask = new Sprite(texture)` (Sprite's transform/position/scale apply to the mask source) |
3106
+ | `runtime.pushMask(rect)` / `runtime.popMask()` | `runtime.pushScissorRect(rect)` / `runtime.popScissorRect()` (renamed; behavior unchanged) |
3107
+ | `class Group extends SceneNode { override render() {...} }` | `class Group extends RenderNode { override render() {...} }` |
3108
+ | `class CustomContainer extends Container { override addChild(child: SceneNode) {...} }` | `class CustomContainer extends Container { override addChild(child: RenderNode) {...} }` |
3109
+ | `Scene.create({ update() {...} })` | `new Scene({ update() {...} })` (drop-in replacement; same `this` typing via `ThisType<Scene & T>`) |
3110
+ | `Scene.create({})` | `new Scene()` |
3001
3111
 
3002
3112
  No deprecated aliases are provided. The migration is mechanical and the project is pre-1.0 with explicit "may break between minors" policy.
3003
3113