@lightningjs/renderer 3.0.0-beta9 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (566) hide show
  1. package/LICENSE +202 -202
  2. package/NOTICE +3 -3
  3. package/README.md +230 -147
  4. package/dist/exports/canvas.d.ts +1 -1
  5. package/dist/exports/canvas.js +1 -1
  6. package/dist/exports/canvas.js.map +1 -1
  7. package/dist/exports/index.d.ts +5 -6
  8. package/dist/exports/index.js +3 -5
  9. package/dist/exports/index.js.map +1 -1
  10. package/dist/exports/platform.d.ts +7 -0
  11. package/dist/exports/platform.js +27 -0
  12. package/dist/exports/platform.js.map +1 -0
  13. package/dist/exports/webgl.d.ts +2 -1
  14. package/dist/exports/webgl.js +2 -1
  15. package/dist/exports/webgl.js.map +1 -1
  16. package/dist/src/common/CommonTypes.d.ts +15 -3
  17. package/dist/src/core/AutosizeManager.d.ts +29 -0
  18. package/dist/src/core/AutosizeManager.js +169 -0
  19. package/dist/src/core/AutosizeManager.js.map +1 -0
  20. package/dist/src/core/Autosizer.d.ts +35 -0
  21. package/dist/src/core/Autosizer.js +196 -0
  22. package/dist/src/core/Autosizer.js.map +1 -0
  23. package/dist/src/core/CoreNode.d.ts +106 -58
  24. package/dist/src/core/CoreNode.js +524 -282
  25. package/dist/src/core/CoreNode.js.map +1 -1
  26. package/dist/src/core/CoreTextNode.d.ts +73 -88
  27. package/dist/src/core/CoreTextNode.js +375 -236
  28. package/dist/src/core/CoreTextNode.js.map +1 -1
  29. package/dist/src/core/CoreTextureManager.d.ts +19 -17
  30. package/dist/src/core/CoreTextureManager.js +52 -120
  31. package/dist/src/core/CoreTextureManager.js.map +1 -1
  32. package/dist/src/core/Stage.d.ts +63 -9
  33. package/dist/src/core/Stage.js +233 -133
  34. package/dist/src/core/Stage.js.map +1 -1
  35. package/dist/src/core/TextureError.d.ts +11 -0
  36. package/dist/src/core/TextureError.js +37 -0
  37. package/dist/src/core/TextureError.js.map +1 -0
  38. package/dist/src/core/TextureMemoryManager.d.ts +2 -4
  39. package/dist/src/core/TextureMemoryManager.js +80 -113
  40. package/dist/src/core/TextureMemoryManager.js.map +1 -1
  41. package/dist/src/core/animations/Animation.d.ts +21 -0
  42. package/dist/src/core/animations/Animation.js +194 -0
  43. package/dist/src/core/animations/Animation.js.map +1 -0
  44. package/dist/src/core/animations/CoreAnimation.d.ts +3 -3
  45. package/dist/src/core/animations/CoreAnimation.js +3 -3
  46. package/dist/src/core/animations/CoreAnimation.js.map +1 -1
  47. package/dist/src/core/animations/CoreAnimationController.d.ts +1 -1
  48. package/dist/src/core/animations/CoreAnimationController.js +4 -2
  49. package/dist/src/core/animations/CoreAnimationController.js.map +1 -1
  50. package/dist/src/core/animations/Playback.d.ts +64 -0
  51. package/dist/src/core/animations/Playback.js +169 -0
  52. package/dist/src/core/animations/Playback.js.map +1 -0
  53. package/dist/src/core/animations/Transition.d.ts +27 -0
  54. package/dist/src/core/animations/Transition.js +52 -0
  55. package/dist/src/core/animations/Transition.js.map +1 -0
  56. package/dist/src/core/animations/utils.d.ts +2 -0
  57. package/dist/src/core/animations/utils.js +136 -0
  58. package/dist/src/core/animations/utils.js.map +1 -0
  59. package/dist/src/core/lib/ImageWorker.d.ts +2 -2
  60. package/dist/src/core/lib/ImageWorker.js +30 -11
  61. package/dist/src/core/lib/ImageWorker.js.map +1 -1
  62. package/dist/src/core/lib/WebGlContextWrapper.d.ts +22 -1
  63. package/dist/src/core/lib/WebGlContextWrapper.js +49 -3
  64. package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -1
  65. package/dist/src/core/lib/collectionUtils.d.ts +4 -0
  66. package/dist/src/core/lib/collectionUtils.js +72 -0
  67. package/dist/src/core/lib/collectionUtils.js.map +1 -0
  68. package/dist/src/core/lib/colorCache.d.ts +1 -0
  69. package/dist/src/core/lib/colorCache.js +19 -0
  70. package/dist/src/core/lib/colorCache.js.map +1 -0
  71. package/dist/src/core/lib/colorParser.d.ts +21 -0
  72. package/dist/src/core/lib/colorParser.js +72 -0
  73. package/dist/src/core/lib/colorParser.js.map +1 -0
  74. package/dist/src/core/lib/textureCompression.d.ts +14 -2
  75. package/dist/src/core/lib/textureCompression.js +320 -67
  76. package/dist/src/core/lib/textureCompression.js.map +1 -1
  77. package/dist/src/core/lib/utils.d.ts +6 -6
  78. package/dist/src/core/lib/utils.js +21 -65
  79. package/dist/src/core/lib/utils.js.map +1 -1
  80. package/dist/src/core/platform.d.ts +10 -0
  81. package/dist/src/core/platform.js +81 -0
  82. package/dist/src/core/platform.js.map +1 -0
  83. package/dist/src/core/platforms/GlContextWrapper.d.ts +136 -0
  84. package/{src/core/text-rendering/TextRenderingUtils.ts → dist/src/core/platforms/GlContextWrapper.js} +32 -36
  85. package/dist/src/core/platforms/GlContextWrapper.js.map +1 -0
  86. package/dist/src/core/platforms/Platform.d.ts +78 -12
  87. package/dist/src/core/platforms/Platform.js +18 -0
  88. package/dist/src/core/platforms/Platform.js.map +1 -1
  89. package/dist/src/core/platforms/web/WebGlContextWrapper.d.ts +776 -0
  90. package/dist/src/core/platforms/web/WebGlContextWrapper.js +1208 -0
  91. package/dist/src/core/platforms/web/WebGlContextWrapper.js.map +1 -0
  92. package/dist/src/core/platforms/web/WebPlatform.d.ts +17 -2
  93. package/dist/src/core/platforms/web/WebPlatform.js +158 -13
  94. package/dist/src/core/platforms/web/WebPlatform.js.map +1 -1
  95. package/dist/src/core/platforms/web/WebPlatformChrome50.d.ts +19 -0
  96. package/dist/src/core/platforms/web/WebPlatformChrome50.js +54 -0
  97. package/dist/src/core/platforms/web/WebPlatformChrome50.js.map +1 -0
  98. package/dist/src/core/platforms/web/WebPlatformLegacy.d.ts +20 -0
  99. package/dist/src/core/platforms/web/WebPlatformLegacy.js +105 -0
  100. package/dist/src/core/platforms/web/WebPlatformLegacy.js.map +1 -0
  101. package/dist/src/core/platforms/web/WebPlatformNext.d.ts +21 -0
  102. package/dist/src/core/platforms/web/WebPlatformNext.js +52 -0
  103. package/dist/src/core/platforms/web/WebPlatformNext.js.map +1 -0
  104. package/dist/src/core/platforms/web/lib/ImageWorker.d.ts +21 -0
  105. package/dist/src/core/platforms/web/lib/ImageWorker.js +136 -0
  106. package/dist/src/core/platforms/web/lib/ImageWorker.js.map +1 -0
  107. package/dist/src/core/platforms/web/lib/ImageWorkerDefault.d.ts +6 -0
  108. package/dist/src/core/platforms/web/lib/ImageWorkerDefault.js +92 -0
  109. package/dist/src/core/platforms/web/lib/ImageWorkerDefault.js.map +1 -0
  110. package/dist/src/core/platforms/web/lib/ImageWorkerLegacy.d.ts +1 -0
  111. package/dist/src/core/platforms/web/lib/ImageWorkerLegacy.js +63 -0
  112. package/dist/src/core/platforms/web/lib/ImageWorkerLegacy.js.map +1 -0
  113. package/dist/src/core/platforms/web/lib/ImageWorkerNoOptions.d.ts +7 -0
  114. package/dist/src/core/platforms/web/lib/ImageWorkerNoOptions.js +75 -0
  115. package/dist/src/core/platforms/web/lib/ImageWorkerNoOptions.js.map +1 -0
  116. package/dist/src/core/platforms/web/lib/createImageBitmap.d.ts +1 -0
  117. package/dist/src/core/platforms/web/lib/createImageBitmap.js +27 -0
  118. package/dist/src/core/platforms/web/lib/createImageBitmap.js.map +1 -0
  119. package/dist/src/core/platforms/web/lib/textureCompression.d.ts +26 -0
  120. package/dist/src/core/platforms/web/lib/textureCompression.js +301 -0
  121. package/dist/src/core/platforms/web/lib/textureCompression.js.map +1 -0
  122. package/dist/src/core/platforms/web/lib/textureSvg.d.ts +7 -0
  123. package/dist/src/core/platforms/web/lib/textureSvg.js +51 -0
  124. package/dist/src/core/platforms/web/lib/textureSvg.js.map +1 -0
  125. package/dist/src/core/platforms/web/lib/utils.d.ts +5 -0
  126. package/dist/src/core/platforms/web/lib/utils.js +86 -0
  127. package/dist/src/core/platforms/web/lib/utils.js.map +1 -0
  128. package/dist/src/core/renderers/CoreContextTexture.d.ts +2 -1
  129. package/dist/src/core/renderers/CoreContextTexture.js.map +1 -1
  130. package/dist/src/core/renderers/CoreRenderer.d.ts +4 -40
  131. package/dist/src/core/renderers/CoreRenderer.js +3 -4
  132. package/dist/src/core/renderers/CoreRenderer.js.map +1 -1
  133. package/dist/src/core/renderers/CoreShader.d.ts +9 -0
  134. package/{src/core/text-rendering/renderers/SdfTextRenderer/internal/constants.ts → dist/src/core/renderers/CoreShader.js} +28 -32
  135. package/dist/src/core/renderers/CoreShader.js.map +1 -0
  136. package/dist/src/core/renderers/CoreShaderNode.d.ts +10 -0
  137. package/dist/src/core/renderers/CoreShaderNode.js +19 -2
  138. package/dist/src/core/renderers/CoreShaderNode.js.map +1 -1
  139. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.d.ts +33 -0
  140. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.js +250 -0
  141. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.js.map +1 -0
  142. package/dist/src/core/renderers/canvas/CanvasCoreTexture.d.ts +17 -0
  143. package/dist/src/core/renderers/canvas/CanvasCoreTexture.js +125 -0
  144. package/dist/src/core/renderers/canvas/CanvasCoreTexture.js.map +1 -0
  145. package/dist/src/core/renderers/canvas/CanvasRenderer.d.ts +5 -6
  146. package/dist/src/core/renderers/canvas/CanvasRenderer.js +67 -91
  147. package/dist/src/core/renderers/canvas/CanvasRenderer.js.map +1 -1
  148. package/dist/src/core/renderers/canvas/CanvasShaderNode.d.ts +1 -2
  149. package/dist/src/core/renderers/canvas/CanvasShaderNode.js +5 -4
  150. package/dist/src/core/renderers/canvas/CanvasShaderNode.js.map +1 -1
  151. package/dist/src/core/renderers/canvas/CanvasTexture.d.ts +3 -2
  152. package/dist/src/core/renderers/canvas/CanvasTexture.js +17 -13
  153. package/dist/src/core/renderers/canvas/CanvasTexture.js.map +1 -1
  154. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.d.ts +13 -0
  155. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.js +113 -192
  156. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.js.map +1 -1
  157. package/dist/src/core/renderers/canvas/internal/ColorUtils.d.ts +0 -2
  158. package/dist/src/core/renderers/canvas/internal/ColorUtils.js +0 -14
  159. package/dist/src/core/renderers/canvas/internal/ColorUtils.js.map +1 -1
  160. package/dist/src/core/renderers/canvas/shaders/UnsupportedShader.d.ts +10 -0
  161. package/{src/core/text-rendering/renderers/SdfTextRenderer/internal/util.ts → dist/src/core/renderers/canvas/shaders/UnsupportedShader.js} +43 -40
  162. package/dist/src/core/renderers/canvas/shaders/UnsupportedShader.js.map +1 -0
  163. package/dist/src/core/renderers/webgl/SdfRenderOp.d.ts +33 -0
  164. package/dist/src/core/renderers/webgl/SdfRenderOp.js +98 -0
  165. package/dist/src/core/renderers/webgl/SdfRenderOp.js.map +1 -0
  166. package/dist/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.d.ts +12 -0
  167. package/dist/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.js +58 -0
  168. package/dist/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.js.map +1 -0
  169. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.d.ts +9 -0
  170. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js +38 -0
  171. package/dist/src/core/renderers/webgl/WebGlCoreCtxSubTexture.js.map +1 -0
  172. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.d.ts +69 -0
  173. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +272 -0
  174. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -0
  175. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.d.ts +34 -0
  176. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js +114 -0
  177. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js.map +1 -0
  178. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.d.ts +133 -0
  179. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +649 -0
  180. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -0
  181. package/dist/src/core/renderers/webgl/WebGlCoreShader.d.ts +78 -0
  182. package/dist/src/core/renderers/webgl/WebGlCoreShader.js +202 -0
  183. package/dist/src/core/renderers/webgl/WebGlCoreShader.js.map +1 -0
  184. package/dist/src/core/renderers/webgl/WebGlCtxRenderTexture.d.ts +4 -2
  185. package/dist/src/core/renderers/webgl/WebGlCtxRenderTexture.js +14 -6
  186. package/dist/src/core/renderers/webgl/WebGlCtxRenderTexture.js.map +1 -1
  187. package/dist/src/core/renderers/webgl/WebGlCtxSubTexture.d.ts +15 -2
  188. package/dist/src/core/renderers/webgl/WebGlCtxSubTexture.js +34 -5
  189. package/dist/src/core/renderers/webgl/WebGlCtxSubTexture.js.map +1 -1
  190. package/dist/src/core/renderers/webgl/WebGlCtxTexture.d.ts +19 -9
  191. package/dist/src/core/renderers/webgl/WebGlCtxTexture.js +101 -49
  192. package/dist/src/core/renderers/webgl/WebGlCtxTexture.js.map +1 -1
  193. package/dist/src/core/renderers/webgl/WebGlRenderOp.d.ts +3 -2
  194. package/dist/src/core/renderers/webgl/WebGlRenderOp.js +14 -5
  195. package/dist/src/core/renderers/webgl/WebGlRenderOp.js.map +1 -1
  196. package/dist/src/core/renderers/webgl/WebGlRenderer.d.ts +11 -23
  197. package/dist/src/core/renderers/webgl/WebGlRenderer.js +122 -133
  198. package/dist/src/core/renderers/webgl/WebGlRenderer.js.map +1 -1
  199. package/dist/src/core/renderers/webgl/WebGlShaderNode.d.ts +4 -6
  200. package/dist/src/core/renderers/webgl/WebGlShaderNode.js +3 -3
  201. package/dist/src/core/renderers/webgl/WebGlShaderNode.js.map +1 -1
  202. package/dist/src/core/renderers/webgl/WebGlShaderProgram.d.ts +7 -7
  203. package/dist/src/core/renderers/webgl/WebGlShaderProgram.js +56 -37
  204. package/dist/src/core/renderers/webgl/WebGlShaderProgram.js.map +1 -1
  205. package/dist/src/core/renderers/webgl/internal/RendererUtils.d.ts +4 -4
  206. package/dist/src/core/renderers/webgl/internal/RendererUtils.js.map +1 -1
  207. package/dist/src/core/renderers/webgl/internal/ShaderUtils.d.ts +3 -3
  208. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js +38 -37
  209. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js.map +1 -1
  210. package/dist/src/core/renderers/webgl/shaders/DefaultShader.d.ts +9 -0
  211. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js +84 -0
  212. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js.map +1 -0
  213. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.d.ts +10 -0
  214. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js +108 -0
  215. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js.map +1 -0
  216. package/dist/src/core/renderers/webgl/shaders/DynamicShader.d.ts +29 -0
  217. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js +408 -0
  218. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js.map +1 -0
  219. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.d.ts +28 -0
  220. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js +126 -0
  221. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js.map +1 -0
  222. package/dist/src/core/renderers/webgl/shaders/SdfShader.d.ts +47 -0
  223. package/dist/src/core/renderers/webgl/shaders/SdfShader.js +148 -0
  224. package/dist/src/core/renderers/webgl/shaders/SdfShader.js.map +1 -0
  225. package/dist/src/core/renderers/webgl/shaders/effects/BorderBottomEffect.d.ts +31 -0
  226. package/dist/src/core/renderers/webgl/shaders/effects/BorderBottomEffect.js +71 -0
  227. package/dist/src/core/renderers/webgl/shaders/effects/BorderBottomEffect.js.map +1 -0
  228. package/dist/src/core/renderers/webgl/shaders/effects/BorderEffect.d.ts +30 -0
  229. package/dist/src/core/renderers/webgl/shaders/effects/BorderEffect.js +58 -0
  230. package/dist/src/core/renderers/webgl/shaders/effects/BorderEffect.js.map +1 -0
  231. package/dist/src/core/renderers/webgl/shaders/effects/BorderLeftEffect.d.ts +31 -0
  232. package/dist/src/core/renderers/webgl/shaders/effects/BorderLeftEffect.js +71 -0
  233. package/dist/src/core/renderers/webgl/shaders/effects/BorderLeftEffect.js.map +1 -0
  234. package/dist/src/core/renderers/webgl/shaders/effects/BorderRightEffect.d.ts +31 -0
  235. package/dist/src/core/renderers/webgl/shaders/effects/BorderRightEffect.js +71 -0
  236. package/dist/src/core/renderers/webgl/shaders/effects/BorderRightEffect.js.map +1 -0
  237. package/dist/src/core/renderers/webgl/shaders/effects/BorderTopEffect.d.ts +31 -0
  238. package/dist/src/core/renderers/webgl/shaders/effects/BorderTopEffect.js +71 -0
  239. package/dist/src/core/renderers/webgl/shaders/effects/BorderTopEffect.js.map +1 -0
  240. package/dist/src/core/renderers/webgl/shaders/effects/EffectUtils.d.ts +9 -0
  241. package/dist/src/core/renderers/webgl/shaders/effects/EffectUtils.js +136 -0
  242. package/dist/src/core/renderers/webgl/shaders/effects/EffectUtils.js.map +1 -0
  243. package/dist/src/core/renderers/webgl/shaders/effects/FadeOutEffect.d.ts +36 -0
  244. package/dist/src/core/renderers/webgl/shaders/effects/FadeOutEffect.js +85 -0
  245. package/dist/src/core/renderers/webgl/shaders/effects/FadeOutEffect.js.map +1 -0
  246. package/dist/src/core/renderers/webgl/shaders/effects/GlitchEffect.d.ts +45 -0
  247. package/dist/src/core/renderers/webgl/shaders/effects/GlitchEffect.js +104 -0
  248. package/dist/src/core/renderers/webgl/shaders/effects/GlitchEffect.js.map +1 -0
  249. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.d.ts +22 -0
  250. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js +45 -0
  251. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js.map +1 -0
  252. package/dist/src/core/renderers/webgl/shaders/effects/HolePunchEffect.d.ts +58 -0
  253. package/dist/src/core/renderers/webgl/shaders/effects/HolePunchEffect.js +80 -0
  254. package/dist/src/core/renderers/webgl/shaders/effects/HolePunchEffect.js.map +1 -0
  255. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.d.ts +35 -0
  256. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js +134 -0
  257. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js.map +1 -0
  258. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.d.ts +40 -0
  259. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js +143 -0
  260. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js.map +1 -0
  261. package/dist/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.d.ts +61 -0
  262. package/dist/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.js +127 -0
  263. package/dist/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.js.map +1 -0
  264. package/dist/src/core/renderers/webgl/shaders/effects/RadiusEffect.d.ts +40 -0
  265. package/dist/src/core/renderers/webgl/shaders/effects/RadiusEffect.js +71 -0
  266. package/dist/src/core/renderers/webgl/shaders/effects/RadiusEffect.js.map +1 -0
  267. package/dist/src/core/renderers/webgl/shaders/effects/ShaderEffect.d.ts +115 -0
  268. package/dist/src/core/renderers/webgl/shaders/effects/ShaderEffect.js +61 -0
  269. package/dist/src/core/renderers/webgl/shaders/effects/ShaderEffect.js.map +1 -0
  270. package/dist/src/core/shaders/canvas/Border.d.ts +8 -2
  271. package/dist/src/core/shaders/canvas/Border.js +64 -25
  272. package/dist/src/core/shaders/canvas/Border.js.map +1 -1
  273. package/dist/src/core/shaders/canvas/HolePunch.js +4 -3
  274. package/dist/src/core/shaders/canvas/HolePunch.js.map +1 -1
  275. package/dist/src/core/shaders/canvas/LinearGradient.js +7 -5
  276. package/dist/src/core/shaders/canvas/LinearGradient.js.map +1 -1
  277. package/dist/src/core/shaders/canvas/RadialGradient.js +12 -10
  278. package/dist/src/core/shaders/canvas/RadialGradient.js.map +1 -1
  279. package/dist/src/core/shaders/canvas/Rounded.js +3 -3
  280. package/dist/src/core/shaders/canvas/Rounded.js.map +1 -1
  281. package/dist/src/core/shaders/canvas/RoundedWithBorder.d.ts +6 -3
  282. package/dist/src/core/shaders/canvas/RoundedWithBorder.js +41 -11
  283. package/dist/src/core/shaders/canvas/RoundedWithBorder.js.map +1 -1
  284. package/dist/src/core/shaders/canvas/RoundedWithBorderAndShadow.d.ts +2 -3
  285. package/dist/src/core/shaders/canvas/RoundedWithBorderAndShadow.js +46 -9
  286. package/dist/src/core/shaders/canvas/RoundedWithBorderAndShadow.js.map +1 -1
  287. package/dist/src/core/shaders/canvas/RoundedWithShadow.js +6 -5
  288. package/dist/src/core/shaders/canvas/RoundedWithShadow.js.map +1 -1
  289. package/dist/src/core/shaders/canvas/Shadow.js +4 -2
  290. package/dist/src/core/shaders/canvas/Shadow.js.map +1 -1
  291. package/dist/src/core/shaders/canvas/utils/render.d.ts +1 -1
  292. package/dist/src/core/shaders/canvas/utils/render.js +31 -18
  293. package/dist/src/core/shaders/canvas/utils/render.js.map +1 -1
  294. package/dist/src/core/shaders/templates/BorderTemplate.d.ts +11 -1
  295. package/dist/src/core/shaders/templates/BorderTemplate.js +30 -10
  296. package/dist/src/core/shaders/templates/BorderTemplate.js.map +1 -1
  297. package/dist/src/core/shaders/templates/HolePunchTemplate.d.ts +2 -2
  298. package/dist/src/core/shaders/templates/HolePunchTemplate.js +2 -2
  299. package/dist/src/core/shaders/templates/HolePunchTemplate.js.map +1 -1
  300. package/dist/src/core/shaders/templates/RadialGradientTemplate.d.ts +8 -6
  301. package/dist/src/core/shaders/templates/RadialGradientTemplate.js +2 -2
  302. package/dist/src/core/shaders/templates/RadialGradientTemplate.js.map +1 -1
  303. package/dist/src/core/shaders/webgl/Border.js +138 -84
  304. package/dist/src/core/shaders/webgl/Border.js.map +1 -1
  305. package/dist/src/core/shaders/webgl/Default.js +46 -47
  306. package/dist/src/core/shaders/webgl/Default.js.map +1 -1
  307. package/dist/src/core/shaders/webgl/DefaultBatched.js +61 -61
  308. package/dist/src/core/shaders/webgl/HolePunch.js +34 -34
  309. package/dist/src/core/shaders/webgl/HolePunch.js.map +1 -1
  310. package/dist/src/core/shaders/webgl/LinearGradient.js +60 -36
  311. package/dist/src/core/shaders/webgl/LinearGradient.js.map +1 -1
  312. package/dist/src/core/shaders/webgl/RadialGradient.js +60 -37
  313. package/dist/src/core/shaders/webgl/RadialGradient.js.map +1 -1
  314. package/dist/src/core/shaders/webgl/Rounded.js +74 -72
  315. package/dist/src/core/shaders/webgl/Rounded.js.map +1 -1
  316. package/dist/src/core/shaders/webgl/RoundedWithBorder.js +172 -113
  317. package/dist/src/core/shaders/webgl/RoundedWithBorder.js.map +1 -1
  318. package/dist/src/core/shaders/webgl/RoundedWithBorderAndShadow.js +191 -132
  319. package/dist/src/core/shaders/webgl/RoundedWithBorderAndShadow.js.map +1 -1
  320. package/dist/src/core/shaders/webgl/RoundedWithShadow.js +57 -55
  321. package/dist/src/core/shaders/webgl/RoundedWithShadow.js.map +1 -1
  322. package/dist/src/core/shaders/webgl/SdfShader.d.ts +0 -2
  323. package/dist/src/core/shaders/webgl/SdfShader.js +56 -66
  324. package/dist/src/core/shaders/webgl/SdfShader.js.map +1 -1
  325. package/dist/src/core/shaders/webgl/SdfShadowShader.d.ts +9 -0
  326. package/dist/src/core/shaders/webgl/SdfShadowShader.js +100 -0
  327. package/dist/src/core/shaders/webgl/SdfShadowShader.js.map +1 -0
  328. package/dist/src/core/shaders/webgl/Shadow.js +89 -83
  329. package/dist/src/core/shaders/webgl/Shadow.js.map +1 -1
  330. package/dist/src/core/text-rendering/CanvasFont.d.ts +14 -0
  331. package/dist/src/core/text-rendering/CanvasFont.js +111 -0
  332. package/dist/src/core/text-rendering/CanvasFont.js.map +1 -0
  333. package/dist/src/core/text-rendering/CanvasFontHandler.d.ts +59 -0
  334. package/dist/src/core/text-rendering/CanvasFontHandler.js +224 -0
  335. package/dist/src/core/text-rendering/CanvasFontHandler.js.map +1 -0
  336. package/dist/src/core/text-rendering/CanvasTextRenderer.d.ts +17 -0
  337. package/dist/src/core/text-rendering/CanvasTextRenderer.js +157 -0
  338. package/dist/src/core/text-rendering/CanvasTextRenderer.js.map +1 -0
  339. package/dist/src/core/text-rendering/CoreFont.d.ts +33 -0
  340. package/dist/src/core/text-rendering/CoreFont.js +48 -0
  341. package/dist/src/core/text-rendering/CoreFont.js.map +1 -0
  342. package/dist/src/core/text-rendering/FontManager.d.ts +11 -0
  343. package/dist/src/core/text-rendering/FontManager.js +42 -0
  344. package/dist/src/core/text-rendering/FontManager.js.map +1 -0
  345. package/dist/src/core/text-rendering/SdfFont.d.ts +29 -0
  346. package/dist/src/core/text-rendering/SdfFont.js +142 -0
  347. package/dist/src/core/text-rendering/SdfFont.js.map +1 -0
  348. package/dist/src/core/text-rendering/SdfFontHandler.d.ts +182 -0
  349. package/dist/src/core/text-rendering/SdfFontHandler.js +381 -0
  350. package/dist/src/core/text-rendering/SdfFontHandler.js.map +1 -0
  351. package/dist/src/core/text-rendering/SdfTextRenderer.d.ts +17 -0
  352. package/dist/src/core/text-rendering/SdfTextRenderer.js +301 -0
  353. package/dist/src/core/text-rendering/SdfTextRenderer.js.map +1 -0
  354. package/dist/src/core/text-rendering/TextLayoutEngine.d.ts +18 -0
  355. package/dist/src/core/text-rendering/TextLayoutEngine.js +380 -0
  356. package/dist/src/core/text-rendering/TextLayoutEngine.js.map +1 -0
  357. package/dist/src/core/text-rendering/TextRenderer.d.ts +383 -0
  358. package/{src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.ts → dist/src/core/text-rendering/TextRenderer.js} +20 -38
  359. package/dist/src/core/text-rendering/TextRenderer.js.map +1 -0
  360. package/dist/src/core/text-rendering/TextTextureRendererUtils.js.map +1 -1
  361. package/dist/src/core/text-rendering/Utils.d.ts +30 -0
  362. package/dist/src/core/text-rendering/Utils.js +84 -0
  363. package/dist/src/core/text-rendering/Utils.js.map +1 -0
  364. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js +2 -2
  365. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js.map +1 -1
  366. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +0 -5
  367. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
  368. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.d.ts +1 -7
  369. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js +2 -50
  370. package/dist/src/core/text-rendering/renderers/LightningTextTextureRenderer.js.map +1 -1
  371. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +3 -2
  372. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +87 -46
  373. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
  374. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.d.ts +1 -1
  375. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js +8 -66
  376. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js.map +1 -1
  377. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +4 -14
  378. package/dist/src/core/text-rendering/renderers/TextRenderer.js +0 -3
  379. package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
  380. package/dist/src/core/textures/ColorTexture.d.ts +1 -1
  381. package/dist/src/core/textures/ColorTexture.js +3 -4
  382. package/dist/src/core/textures/ColorTexture.js.map +1 -1
  383. package/dist/src/core/textures/ImageTexture.d.ts +33 -14
  384. package/dist/src/core/textures/ImageTexture.js +46 -125
  385. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  386. package/dist/src/core/textures/NoiseTexture.d.ts +3 -3
  387. package/dist/src/core/textures/NoiseTexture.js +8 -8
  388. package/dist/src/core/textures/NoiseTexture.js.map +1 -1
  389. package/dist/src/core/textures/RenderTexture.d.ts +7 -7
  390. package/dist/src/core/textures/RenderTexture.js +12 -12
  391. package/dist/src/core/textures/RenderTexture.js.map +1 -1
  392. package/dist/src/core/textures/SubTexture.d.ts +6 -8
  393. package/dist/src/core/textures/SubTexture.js +22 -40
  394. package/dist/src/core/textures/SubTexture.js.map +1 -1
  395. package/dist/src/core/textures/Texture.d.ts +74 -15
  396. package/dist/src/core/textures/Texture.js +131 -19
  397. package/dist/src/core/textures/Texture.js.map +1 -1
  398. package/dist/src/core/utils.d.ts +2 -1
  399. package/dist/src/core/utils.js +1 -1
  400. package/dist/src/core/utils.js.map +1 -1
  401. package/dist/src/main-api/DynamicShaderController.d.ts +29 -0
  402. package/dist/src/main-api/DynamicShaderController.js +58 -0
  403. package/dist/src/main-api/DynamicShaderController.js.map +1 -0
  404. package/dist/src/main-api/Inspector.d.ts +129 -1
  405. package/dist/src/main-api/Inspector.js +462 -23
  406. package/dist/src/main-api/Inspector.js.map +1 -1
  407. package/dist/src/main-api/Renderer.d.ts +223 -41
  408. package/dist/src/main-api/Renderer.js +107 -62
  409. package/dist/src/main-api/Renderer.js.map +1 -1
  410. package/dist/src/main-api/ShaderController.d.ts +31 -0
  411. package/dist/src/main-api/ShaderController.js +37 -0
  412. package/dist/src/main-api/ShaderController.js.map +1 -0
  413. package/dist/src/utils.d.ts +0 -2
  414. package/dist/src/utils.js +0 -36
  415. package/dist/src/utils.js.map +1 -1
  416. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  417. package/dist/tsconfig.tsbuildinfo +1 -0
  418. package/exports/canvas-shaders.ts +28 -28
  419. package/exports/canvas.ts +45 -45
  420. package/exports/index.ts +90 -90
  421. package/exports/inspector.ts +24 -24
  422. package/exports/platform.ts +31 -0
  423. package/exports/utils.ts +50 -50
  424. package/exports/webgl-shaders.ts +28 -28
  425. package/exports/webgl.ts +52 -50
  426. package/package.json +16 -15
  427. package/src/common/CommonTypes.ts +163 -146
  428. package/src/common/EventEmitter.ts +77 -77
  429. package/src/common/IAnimationController.ts +92 -92
  430. package/src/common/IEventEmitter.ts +28 -28
  431. package/src/core/Autosizer.ts +224 -0
  432. package/src/core/CoreNode.test.ts +365 -202
  433. package/src/core/CoreNode.ts +2785 -2489
  434. package/src/core/CoreShaderManager.ts +188 -188
  435. package/src/core/CoreTextNode.test.ts +311 -0
  436. package/src/core/CoreTextNode.ts +598 -451
  437. package/src/core/CoreTextureManager.ts +484 -548
  438. package/src/core/Stage.ts +927 -800
  439. package/src/core/TextureError.ts +46 -0
  440. package/src/core/TextureMemoryManager.ts +418 -462
  441. package/src/core/animations/AnimationManager.ts +38 -38
  442. package/src/core/animations/CoreAnimation.ts +290 -291
  443. package/src/core/animations/CoreAnimationController.ts +169 -166
  444. package/src/core/lib/ContextSpy.ts +41 -41
  445. package/src/core/lib/Matrix3d.ts +244 -244
  446. package/src/core/lib/RenderCoords.ts +71 -71
  447. package/src/core/lib/collectionUtils.ts +83 -0
  448. package/src/core/lib/colorCache.ts +20 -0
  449. package/src/core/{renderers/canvas/internal/ColorUtils.ts → lib/colorParser.ts} +85 -85
  450. package/src/core/lib/utils.ts +337 -390
  451. package/src/core/platforms/GlContextWrapper.ts +291 -0
  452. package/src/core/platforms/Platform.ts +176 -77
  453. package/src/core/{lib → platforms/web}/WebGlContextWrapper.ts +1547 -1368
  454. package/src/core/platforms/web/WebPlatform.ts +306 -84
  455. package/src/core/platforms/web/WebPlatformChrome50.ts +63 -0
  456. package/src/core/platforms/web/WebPlatformLegacy.ts +150 -0
  457. package/src/core/platforms/web/WebPlatformNext.ts +57 -0
  458. package/src/core/platforms/web/lib/ImageWorker.ts +192 -0
  459. package/src/core/platforms/web/lib/ImageWorkerDefault.ts +117 -0
  460. package/src/core/platforms/web/lib/ImageWorkerLegacy.ts +87 -0
  461. package/src/core/platforms/web/lib/ImageWorkerNoOptions.ts +99 -0
  462. package/src/core/platforms/web/lib/createImageBitmap.ts +40 -0
  463. package/src/core/platforms/web/lib/textureCompression.ts +391 -0
  464. package/src/core/{lib → platforms/web/lib}/textureSvg.ts +66 -78
  465. package/src/core/platforms/web/lib/utils.ts +105 -0
  466. package/src/core/renderers/CoreContextTexture.ts +44 -43
  467. package/src/core/renderers/CoreRenderOp.ts +22 -22
  468. package/src/core/renderers/CoreRenderer.ts +71 -110
  469. package/src/core/renderers/CoreShaderNode.ts +202 -175
  470. package/src/core/renderers/CoreShaderProgram.ts +23 -23
  471. package/src/core/renderers/canvas/CanvasRenderer.ts +258 -302
  472. package/src/core/renderers/canvas/CanvasShaderNode.ts +95 -96
  473. package/src/core/renderers/canvas/CanvasTexture.ts +160 -156
  474. package/src/core/renderers/webgl/SdfRenderOp.ts +106 -0
  475. package/src/core/renderers/webgl/WebGlCtxRenderTexture.ts +89 -86
  476. package/src/core/renderers/webgl/WebGlCtxSubTexture.ts +95 -50
  477. package/src/core/renderers/webgl/WebGlCtxTexture.ts +350 -298
  478. package/src/core/renderers/webgl/WebGlRenderer.ts +726 -747
  479. package/src/core/renderers/webgl/WebGlShaderNode.ts +430 -435
  480. package/src/core/renderers/webgl/WebGlShaderProgram.ts +362 -341
  481. package/src/core/renderers/webgl/internal/BufferCollection.ts +54 -54
  482. package/src/core/renderers/webgl/internal/RendererUtils.ts +151 -155
  483. package/src/core/renderers/webgl/internal/ShaderUtils.ts +283 -281
  484. package/src/core/renderers/webgl/internal/WebGlUtils.ts +35 -35
  485. package/src/core/shaders/canvas/Border.ts +132 -78
  486. package/src/core/shaders/canvas/HolePunch.ts +56 -62
  487. package/src/core/shaders/canvas/LinearGradient.ts +73 -71
  488. package/src/core/shaders/canvas/RadialGradient.ts +96 -99
  489. package/src/core/shaders/canvas/Rounded.ts +55 -55
  490. package/src/core/shaders/canvas/RoundedWithBorder.ts +122 -74
  491. package/src/core/shaders/canvas/RoundedWithBorderAndShadow.ts +136 -90
  492. package/src/core/shaders/canvas/RoundedWithShadow.ts +71 -70
  493. package/src/core/shaders/canvas/Shadow.ts +54 -52
  494. package/src/core/shaders/canvas/utils/render.ts +160 -151
  495. package/src/core/shaders/templates/BorderTemplate.ts +145 -115
  496. package/src/core/shaders/templates/HolePunchTemplate.ts +82 -82
  497. package/src/core/shaders/templates/LinearGradientTemplate.ts +71 -71
  498. package/src/core/shaders/templates/RadialGradientTemplate.ts +83 -81
  499. package/src/core/shaders/templates/RoundedTemplate.ts +98 -98
  500. package/src/core/shaders/templates/RoundedWithBorderAndShadowTemplate.ts +38 -38
  501. package/src/core/shaders/templates/RoundedWithBorderTemplate.ts +35 -35
  502. package/src/core/shaders/templates/RoundedWithShadowTemplate.ts +35 -35
  503. package/src/core/shaders/templates/ShadowTemplate.ts +106 -106
  504. package/src/core/shaders/utils.ts +46 -46
  505. package/src/core/shaders/webgl/Border.ts +169 -116
  506. package/src/core/shaders/webgl/Default.ts +88 -89
  507. package/src/core/shaders/webgl/DefaultBatched.ts +129 -129
  508. package/src/core/shaders/webgl/HolePunch.ts +75 -75
  509. package/src/core/shaders/webgl/LinearGradient.ts +106 -82
  510. package/src/core/shaders/webgl/RadialGradient.ts +108 -85
  511. package/src/core/shaders/webgl/Rounded.ts +115 -117
  512. package/src/core/shaders/webgl/RoundedWithBorder.ts +210 -155
  513. package/src/core/shaders/webgl/RoundedWithBorderAndShadow.ts +234 -175
  514. package/src/core/shaders/webgl/RoundedWithShadow.ts +96 -98
  515. package/src/core/shaders/webgl/SdfShader.ts +122 -134
  516. package/src/core/shaders/webgl/Shadow.ts +121 -115
  517. package/src/core/text-rendering/CanvasFontHandler.ts +304 -0
  518. package/src/core/text-rendering/CanvasTextRenderer.ts +255 -0
  519. package/src/core/text-rendering/SdfFontHandler.ts +584 -0
  520. package/src/core/text-rendering/SdfTextRenderer.ts +403 -0
  521. package/src/core/text-rendering/TextLayoutEngine.ts +672 -0
  522. package/src/core/text-rendering/TextRenderer.ts +444 -0
  523. package/src/core/text-rendering/Utils.ts +99 -0
  524. package/src/core/text-rendering/tests/TextLayoutEngine.test.ts +453 -0
  525. package/src/core/textures/ColorTexture.ts +104 -102
  526. package/src/core/textures/ImageTexture.ts +292 -418
  527. package/src/core/textures/NoiseTexture.ts +106 -104
  528. package/src/core/textures/RenderTexture.ts +87 -85
  529. package/src/core/textures/SubTexture.ts +184 -205
  530. package/src/core/textures/Texture.ts +524 -381
  531. package/src/core/utils.ts +229 -227
  532. package/src/env.d.ts +7 -7
  533. package/src/main-api/INode.ts +100 -100
  534. package/src/main-api/Inspector.ts +1278 -569
  535. package/src/main-api/Renderer.ts +1030 -818
  536. package/src/main-api/utils.ts +45 -45
  537. package/src/utils.ts +220 -267
  538. package/COPYING +0 -1
  539. package/src/core/lib/ImageWorker.ts +0 -286
  540. package/src/core/lib/textureCompression.ts +0 -152
  541. package/src/core/lib/validateImageBitmap.ts +0 -87
  542. package/src/core/renderers/canvas/internal/C2DShaderUtils.ts +0 -220
  543. package/src/core/renderers/webgl/WebGlRenderOp.ts +0 -161
  544. package/src/core/text-rendering/TextTextureRendererUtils.ts +0 -263
  545. package/src/core/text-rendering/TrFontManager.ts +0 -183
  546. package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +0 -176
  547. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/FontShaper.ts +0 -139
  548. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts +0 -173
  549. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +0 -171
  550. package/src/core/text-rendering/font-face-types/TrFontFace.ts +0 -187
  551. package/src/core/text-rendering/font-face-types/WebTrFontFace.ts +0 -94
  552. package/src/core/text-rendering/font-face-types/utils.ts +0 -39
  553. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +0 -514
  554. package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +0 -863
  555. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +0 -793
  556. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.test.ts +0 -48
  557. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.ts +0 -66
  558. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/SpecialCodepoints.ts +0 -52
  559. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.ts +0 -117
  560. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.test.ts +0 -133
  561. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +0 -497
  562. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts +0 -49
  563. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.ts +0 -52
  564. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.test.ts +0 -205
  565. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.ts +0 -93
  566. package/src/core/text-rendering/renderers/TextRenderer.ts +0 -567
@@ -1,569 +1,1278 @@
1
- import {
2
- CoreNode,
3
- type CoreNodeAnimateProps,
4
- type CoreNodeProps,
5
- } from '../core/CoreNode.js';
6
- import { type RendererMainSettings } from './Renderer.js';
7
- import type { AnimationSettings } from '../core/animations/CoreAnimation.js';
8
- import type { IAnimationController } from '../common/IAnimationController.js';
9
- import { isProductionEnvironment } from '../utils.js';
10
- import { CoreTextNode, type CoreTextNodeProps } from '../core/CoreTextNode.js';
11
-
12
- /**
13
- * Inspector
14
- *
15
- * The inspector is a tool that allows you to inspect the state of the renderer
16
- * and the nodes that are being rendered. It is a tool that is used for debugging
17
- * and development purposes.
18
- *
19
- * The inspector will generate a DOM tree that mirrors the state of the renderer
20
- */
21
-
22
- /**
23
- * stylePropertyMap is a map of renderer properties that are mapped to CSS properties
24
- *
25
- * It can either return a string or an object with a prop and value property. Once a
26
- * property is found in the map, the value is set on the style of the div element.
27
- * Erik H made me do it.
28
- */
29
- interface StyleResponse {
30
- prop: string;
31
- value: string;
32
- }
33
- const stylePropertyMap: {
34
- [key: string]: (
35
- value: string | number | boolean,
36
- ) => string | StyleResponse | null;
37
- } = {
38
- alpha: (v) => {
39
- if (v === 1) {
40
- return null;
41
- }
42
-
43
- return { prop: 'opacity', value: `${v}` };
44
- },
45
- x: (x) => {
46
- return { prop: 'left', value: `${x}px` };
47
- },
48
- y: (y) => {
49
- return { prop: 'top', value: `${y}px` };
50
- },
51
- width: (w) => {
52
- if (w === 0) {
53
- return null;
54
- }
55
-
56
- return { prop: 'width', value: `${w}px` };
57
- },
58
- height: (h) => {
59
- if (h === 0) {
60
- return null;
61
- }
62
-
63
- return { prop: 'height', value: `${h}px` };
64
- },
65
- fontSize: (fs) => {
66
- if (fs === 0) {
67
- return null;
68
- }
69
-
70
- return { prop: 'font-size', value: `${fs}px` };
71
- },
72
- lineHeight: (lh) => {
73
- if (lh === 0) {
74
- return null;
75
- }
76
-
77
- return { prop: 'line-height', value: `${lh}px` };
78
- },
79
- zIndex: () => 'z-index',
80
- fontFamily: () => 'font-family',
81
- fontStyle: () => 'font-style',
82
- fontWeight: () => 'font-weight',
83
- fontStretch: () => 'font-stretch',
84
- letterSpacing: () => 'letter-spacing',
85
- textAlign: () => 'text-align',
86
- overflowSuffix: () => 'overflow-suffix',
87
- maxLines: () => 'max-lines',
88
- contain: () => 'contain',
89
- verticalAlign: () => 'vertical-align',
90
- clipping: (v) => {
91
- if (v === false) {
92
- return null;
93
- }
94
-
95
- return { prop: 'overflow', value: v ? 'hidden' : 'visible' };
96
- },
97
- rotation: (v) => {
98
- if (v === 0) {
99
- return null;
100
- }
101
-
102
- return { prop: 'transform', value: `rotate(${v}rad)` };
103
- },
104
- scale: (v) => {
105
- if (v === 1) {
106
- return null;
107
- }
108
-
109
- return { prop: 'transform', value: `scale(${v})` };
110
- },
111
- scaleX: (v) => {
112
- if (v === 1) {
113
- return null;
114
- }
115
-
116
- return { prop: 'transform', value: `scaleX(${v})` };
117
- },
118
- scaleY: (v) => {
119
- if (v === 1) {
120
- return null;
121
- }
122
-
123
- return { prop: 'transform', value: `scaleY(${v})` };
124
- },
125
- color: (v) => {
126
- if (v === 0) {
127
- return null;
128
- }
129
-
130
- return { prop: 'color', value: convertColorToRgba(v as number) };
131
- },
132
- };
133
-
134
- const convertColorToRgba = (color: number) => {
135
- const a = (color & 0xff) / 255;
136
- const b = (color >> 8) & 0xff;
137
- const g = (color >> 16) & 0xff;
138
- const r = (color >> 24) & 0xff;
139
- return `rgba(${r},${g},${b},${a})`;
140
- };
141
-
142
- const domPropertyMap: { [key: string]: string } = {
143
- id: 'test-id',
144
- };
145
-
146
- const gradientColorPropertyMap = [
147
- 'colorTop',
148
- 'colorBottom',
149
- 'colorLeft',
150
- 'colorRight',
151
- 'colorTl',
152
- 'colorTr',
153
- 'colorBl',
154
- 'colorBr',
155
- ];
156
-
157
- const knownProperties = new Set<string>([
158
- ...Object.keys(stylePropertyMap),
159
- ...Object.keys(domPropertyMap),
160
- // ...gradientColorPropertyMap,
161
- 'src',
162
- 'parent',
163
- 'data',
164
- ]);
165
-
166
- export class Inspector {
167
- private root: HTMLElement | null = null;
168
- private canvas: HTMLCanvasElement | null = null;
169
- private mutationObserver: MutationObserver = new MutationObserver(() => {});
170
- private resizeObserver: ResizeObserver = new ResizeObserver(() => {});
171
- private height = 1080;
172
- private width = 1920;
173
- private scaleX = 1;
174
- private scaleY = 1;
175
-
176
- constructor(canvas: HTMLCanvasElement, settings: RendererMainSettings) {
177
- if (isProductionEnvironment === true) return;
178
-
179
- if (!settings) {
180
- throw new Error('settings is required');
181
- }
182
-
183
- // calc dimensions based on the devicePixelRatio
184
- this.height = Math.ceil(
185
- settings.appHeight ?? 1080 / (settings.deviceLogicalPixelRatio ?? 1),
186
- );
187
-
188
- this.width = Math.ceil(
189
- settings.appWidth ?? 1920 / (settings.deviceLogicalPixelRatio ?? 1),
190
- );
191
-
192
- this.scaleX = settings.deviceLogicalPixelRatio ?? 1;
193
- this.scaleY = settings.deviceLogicalPixelRatio ?? 1;
194
-
195
- this.canvas = canvas;
196
- this.root = document.createElement('div');
197
- this.setRootPosition();
198
- document.body.appendChild(this.root);
199
-
200
- //listen for changes on canvas
201
- this.mutationObserver = new MutationObserver(
202
- this.setRootPosition.bind(this),
203
- );
204
- this.mutationObserver.observe(canvas, {
205
- attributes: true,
206
- childList: false,
207
- subtree: false,
208
- });
209
-
210
- // Create a ResizeObserver to watch for changes in the element's size
211
- this.resizeObserver = new ResizeObserver(this.setRootPosition.bind(this));
212
- this.resizeObserver.observe(canvas);
213
-
214
- //listen for changes on window
215
- window.addEventListener('resize', this.setRootPosition.bind(this));
216
-
217
- console.warn('Inspector is enabled, this will impact performance');
218
- }
219
-
220
- setRootPosition() {
221
- if (this.root === null || this.canvas === null) {
222
- return;
223
- }
224
-
225
- // get the world position of the canvas object, so we can match the inspector to it
226
- const rect = this.canvas.getBoundingClientRect();
227
- const top = document.documentElement.scrollTop + rect.top;
228
- const left = document.documentElement.scrollLeft + rect.left;
229
-
230
- this.root.id = 'root';
231
- this.root.style.left = `${left}px`;
232
- this.root.style.top = `${top}px`;
233
- this.root.style.width = `${this.width}px`;
234
- this.root.style.height = `${this.height}px`;
235
- this.root.style.position = 'absolute';
236
- this.root.style.transformOrigin = '0 0 0';
237
- this.root.style.transform = `scale(${this.scaleX}, ${this.scaleY})`;
238
- this.root.style.overflow = 'hidden';
239
- this.root.style.zIndex = '65534';
240
- }
241
-
242
- createDiv(
243
- id: number,
244
- properties: CoreNodeProps | CoreTextNodeProps,
245
- ): HTMLElement {
246
- const div = document.createElement('div');
247
- div.style.position = 'absolute';
248
- div.id = id.toString();
249
-
250
- // set initial properties
251
- for (const key in properties) {
252
- this.updateNodeProperty(
253
- div,
254
- // really typescript? really?
255
- key as keyof CoreNodeProps,
256
- properties[key as keyof CoreNodeProps],
257
- properties,
258
- );
259
- }
260
-
261
- return div;
262
- }
263
-
264
- createNodes(node: CoreNode): boolean {
265
- if (this.root === null) {
266
- return false;
267
- }
268
-
269
- const div = this.root.querySelector(`[id="${node.id}"]`);
270
- if (div === null && node instanceof CoreTextNode) {
271
- this.createTextNode(node);
272
- } else if (div === null && node instanceof CoreNode) {
273
- this.createNode(node);
274
- }
275
-
276
- for (const child of node.children) {
277
- this.createNodes(child);
278
- }
279
- return true;
280
- }
281
-
282
- createNode(node: CoreNode): CoreNode {
283
- const div = this.createDiv(node.id, node.props);
284
- (div as HTMLElement & { node: CoreNode }).node = node;
285
- (node as CoreNode & { div: HTMLElement }).div = div;
286
-
287
- node.on('inViewport', () => div.setAttribute('state', 'inViewport'));
288
- node.on('inBounds', () => div.setAttribute('state', 'inBounds'));
289
- node.on('outOfBounds', () => div.setAttribute('state', 'outOfBounds'));
290
-
291
- // Monitor only relevant properties by trapping with selective assignment
292
- return this.createProxy(node, div);
293
- }
294
-
295
- createTextNode(node: CoreNode): CoreTextNode {
296
- const div = this.createDiv(node.id, node.props);
297
- (div as HTMLElement & { node: CoreNode }).node = node;
298
- (node as CoreNode & { div: HTMLElement }).div = div;
299
-
300
- return this.createProxy(node, div) as CoreTextNode;
301
- }
302
-
303
- createProxy(
304
- node: CoreNode | CoreTextNode,
305
- div: HTMLElement,
306
- ): CoreNode | CoreTextNode {
307
- // Define traps for each property in knownProperties
308
- knownProperties.forEach((property) => {
309
- let originalProp = Object.getOwnPropertyDescriptor(node, property);
310
-
311
- if (originalProp === undefined) {
312
- // Search the prototype chain for the property descriptor
313
- const proto = Object.getPrototypeOf(node) as CoreNode | CoreTextNode;
314
- originalProp = Object.getOwnPropertyDescriptor(proto, property);
315
- }
316
-
317
- if (originalProp === undefined) {
318
- return;
319
- }
320
-
321
- Object.defineProperty(node, property, {
322
- get() {
323
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
324
- return originalProp?.get?.call(node);
325
- },
326
- set: (value) => {
327
- originalProp?.set?.call(node, value);
328
- this.updateNodeProperty(
329
- div,
330
- property as keyof CoreNodeProps | keyof CoreTextNodeProps,
331
- value,
332
- node.props,
333
- );
334
- },
335
- configurable: true,
336
- enumerable: true,
337
- });
338
- });
339
-
340
- const originalDestroy = node.destroy;
341
- Object.defineProperty(node, 'destroy', {
342
- value: () => {
343
- this.destroyNode(node.id);
344
- originalDestroy.call(node);
345
- },
346
- configurable: true,
347
- });
348
-
349
- const originalAnimate = node.animate;
350
- Object.defineProperty(node, 'animate', {
351
- value: (
352
- props: CoreNodeAnimateProps,
353
- settings: AnimationSettings,
354
- ): IAnimationController => {
355
- const animationController = originalAnimate.call(node, props, settings);
356
-
357
- const originalStart =
358
- animationController.start.bind(animationController);
359
- animationController.start = () => {
360
- this.animateNode(div, props, settings);
361
-
362
- return originalStart();
363
- };
364
-
365
- return animationController;
366
- },
367
- configurable: true,
368
- });
369
-
370
- return node;
371
- }
372
-
373
- public destroy() {
374
- // Remove DOM observers
375
- this.mutationObserver.disconnect();
376
- this.resizeObserver.disconnect();
377
-
378
- // Remove resize listener
379
- window.removeEventListener('resize', this.setRootPosition.bind(this));
380
- if (this.root && this.root.parentNode) {
381
- this.root.remove();
382
- }
383
- }
384
-
385
- destroyNode(id: number) {
386
- const div = document.getElementById(id.toString());
387
- div?.remove();
388
- }
389
-
390
- updateNodeProperty(
391
- div: HTMLElement,
392
- property: keyof CoreNodeProps | keyof CoreTextNodeProps,
393
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
394
- value: any,
395
- props: CoreNodeProps | CoreTextNodeProps,
396
- ) {
397
- if (this.root === null || value === undefined || value === null) {
398
- return;
399
- }
400
-
401
- /**
402
- * Special case for parent property
403
- */
404
- if (property === 'parent') {
405
- const parentId: number = value.id;
406
-
407
- // only way to detect if the parent is the root node
408
- // if you are reading this and have a better way, please let me know
409
- if (parentId === 1) {
410
- this.root.appendChild(div);
411
- return;
412
- }
413
-
414
- const parent = document.getElementById(parentId.toString());
415
- parent?.appendChild(div);
416
- return;
417
- }
418
-
419
- // special case for text
420
- if (property === 'text') {
421
- div.innerHTML = String(value);
422
-
423
- // hide text because we can't render SDF fonts
424
- // it would look weird and obstruct the WebGL rendering
425
- div.style.visibility = 'hidden';
426
- return;
427
- }
428
-
429
- // special case for images
430
- // we're not setting any CSS properties to avoid images getting loaded twice
431
- // as the renderer will handle the loading of the image. Setting it to `data-src`
432
- if (property === 'src' && value) {
433
- div.setAttribute(`data-src`, String(value));
434
- return;
435
- }
436
-
437
- // special case for color gradients (normal colors are handled by the stylePropertyMap)
438
- // FIXME the renderer seems to return the same number for all colors
439
- // if (gradientColorPropertyMap.includes(property as string)) {
440
- // const color = convertColorToRgba(value as number);
441
- // div.setAttribute(`data-${property}`, color);
442
- // return;
443
- // }
444
-
445
- if (property === 'rtt' && value) {
446
- div.setAttribute('data-rtt', String(value));
447
- return;
448
- }
449
-
450
- // CSS mappable attribute
451
- if (stylePropertyMap[property]) {
452
- const mappedStyleResponse = stylePropertyMap[property]?.(value);
453
-
454
- if (mappedStyleResponse === null) {
455
- return;
456
- }
457
-
458
- if (typeof mappedStyleResponse === 'string') {
459
- div.style.setProperty(mappedStyleResponse, String(value));
460
- return;
461
- }
462
-
463
- if (typeof mappedStyleResponse === 'object') {
464
- let value = mappedStyleResponse.value;
465
- if (property === 'x') {
466
- const mount = props.mountX;
467
- const width = props.width;
468
-
469
- if (mount) {
470
- value = `${parseInt(value) - width * mount}px`;
471
- }
472
- } else if (property === 'y') {
473
- const mount = props.mountY;
474
- const height = props.height;
475
-
476
- if (mount) {
477
- value = `${parseInt(value) - height * mount}px`;
478
- }
479
- }
480
- div.style.setProperty(mappedStyleResponse.prop, value);
481
- }
482
-
483
- return;
484
- }
485
-
486
- // DOM properties
487
- if (domPropertyMap[property]) {
488
- const domProperty = domPropertyMap[property];
489
- if (!domProperty) {
490
- return;
491
- }
492
-
493
- div.setAttribute(String(domProperty), String(value));
494
- return;
495
- }
496
-
497
- // custom data properties
498
- if (property === 'data') {
499
- for (const key in value) {
500
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
501
- const keyValue: unknown = value[key];
502
- if (keyValue === undefined) {
503
- div.removeAttribute(`data-${key}`);
504
- } else {
505
- div.setAttribute(`data-${key}`, String(keyValue));
506
- }
507
- }
508
- return;
509
- }
510
- }
511
-
512
- updateViewport(
513
- width: number,
514
- height: number,
515
- deviceLogicalPixelRatio: number,
516
- ) {
517
- this.scaleX = deviceLogicalPixelRatio ?? 1;
518
- this.scaleY = deviceLogicalPixelRatio ?? 1;
519
-
520
- this.width = width;
521
- this.height = height;
522
- this.setRootPosition();
523
- }
524
-
525
- // simple animation handler
526
- animateNode(
527
- div: HTMLElement,
528
- props: CoreNodeAnimateProps,
529
- settings: AnimationSettings,
530
- ) {
531
- const {
532
- duration = 1000,
533
- delay = 0,
534
- // easing = 'linear',
535
- // repeat = 0,
536
- // loop = false,
537
- // stopMethod = false,
538
- } = settings;
539
-
540
- const {
541
- x,
542
- y,
543
- width,
544
- height,
545
- alpha = 1,
546
- rotation = 0,
547
- scale = 1,
548
- color,
549
- mountX,
550
- mountY,
551
- } = props;
552
-
553
- // ignoring loops and repeats for now, as that might be a bit too much for the inspector
554
- function animate() {
555
- setTimeout(() => {
556
- div.style.top = `${y - height * mountY}px`;
557
- div.style.left = `${x - width * mountX}px`;
558
- div.style.width = `${width}px`;
559
- div.style.height = `${height}px`;
560
- div.style.opacity = `${alpha}`;
561
- div.style.rotate = `${rotation}rad`;
562
- div.style.scale = `${scale}`;
563
- div.style.color = convertColorToRgba(color);
564
- }, duration);
565
- }
566
-
567
- setTimeout(animate, delay);
568
- }
569
- }
1
+ import {
2
+ CoreNode,
3
+ type CoreNodeAnimateProps,
4
+ type CoreNodeProps,
5
+ } from '../core/CoreNode.js';
6
+ import { type RendererMainSettings } from './Renderer.js';
7
+ import type { AnimationSettings } from '../core/animations/CoreAnimation.js';
8
+ import type {
9
+ IAnimationController,
10
+ AnimationControllerState,
11
+ } from '../common/IAnimationController.js';
12
+ import { isProductionEnvironment } from '../utils.js';
13
+ import { CoreTextNode, type CoreTextNodeProps } from '../core/CoreTextNode.js';
14
+ import type { Texture } from '../core/textures/Texture.js';
15
+ import { TextureType } from '../core/textures/Texture.js';
16
+
17
+ /**
18
+ * Inspector Options
19
+ *
20
+ * Configuration options for the Inspector's performance monitoring features.
21
+ */
22
+ export interface InspectorOptions {
23
+ /**
24
+ * Enable performance monitoring for setter calls
25
+ *
26
+ * @defaultValue true
27
+ */
28
+ enablePerformanceMonitoring: boolean;
29
+
30
+ /**
31
+ * Threshold for excessive setter calls before logging a warning
32
+ *
33
+ * @defaultValue 100
34
+ */
35
+ excessiveCallThreshold: number;
36
+
37
+ /**
38
+ * Time interval in milliseconds to reset the setter call counters
39
+ *
40
+ * @defaultValue 5000
41
+ */
42
+ resetInterval: number;
43
+
44
+ /**
45
+ * Enable animation monitoring and statistics tracking
46
+ *
47
+ * @defaultValue true
48
+ */
49
+ enableAnimationMonitoring: boolean;
50
+
51
+ /**
52
+ * Maximum number of animations to keep in history for statistics
53
+ *
54
+ * @defaultValue 1000
55
+ */
56
+ maxAnimationHistory: number;
57
+
58
+ /**
59
+ * Automatically print animation statistics every X seconds (0 to disable)
60
+ *
61
+ * @defaultValue 0
62
+ */
63
+ animationStatsInterval: number;
64
+ }
65
+
66
+ /**
67
+ * Inspector
68
+ *
69
+ * The inspector is a tool that allows you to inspect the state of the renderer
70
+ * and the nodes that are being rendered. It is a tool that is used for debugging
71
+ * and development purposes.
72
+ *
73
+ * The inspector will generate a DOM tree that mirrors the state of the renderer
74
+ */
75
+
76
+ /**
77
+ * stylePropertyMap is a map of renderer properties that are mapped to CSS properties
78
+ *
79
+ * It can either return a string or an object with a prop and value property. Once a
80
+ * property is found in the map, the value is set on the style of the div element.
81
+ * Erik H made me do it.
82
+ */
83
+ interface StyleResponse {
84
+ prop: string;
85
+ value: string;
86
+ }
87
+ const stylePropertyMap: {
88
+ [key: string]: (
89
+ value: string | number | boolean,
90
+ ) => string | StyleResponse | null;
91
+ } = {
92
+ alpha: (v) => {
93
+ if (v === 1) {
94
+ return null;
95
+ }
96
+
97
+ return { prop: 'opacity', value: `${v}` };
98
+ },
99
+ x: (x) => {
100
+ return { prop: 'left', value: `${x}px` };
101
+ },
102
+ y: (y) => {
103
+ return { prop: 'top', value: `${y}px` };
104
+ },
105
+ w: (w) => {
106
+ if (w === 0) {
107
+ return { prop: 'width', value: 'auto' };
108
+ }
109
+
110
+ return { prop: 'width', value: `${w}px` };
111
+ },
112
+ h: (h) => {
113
+ if (h === 0) {
114
+ return { prop: 'height', value: 'auto' };
115
+ }
116
+
117
+ return { prop: 'height', value: `${h}px` };
118
+ },
119
+ fontSize: (fs) => {
120
+ if (fs === 0) {
121
+ return null;
122
+ }
123
+
124
+ return { prop: 'font-size', value: `${fs}px` };
125
+ },
126
+ lineHeight: (lh) => {
127
+ if (lh === 0) {
128
+ return null;
129
+ }
130
+
131
+ return { prop: 'line-height', value: `${lh}px` };
132
+ },
133
+ zIndex: () => 'z-index',
134
+ fontFamily: () => 'font-family',
135
+ fontStyle: () => 'font-style',
136
+ letterSpacing: () => 'letter-spacing',
137
+ textAlign: () => 'text-align',
138
+ overflowSuffix: () => 'overflow-suffix',
139
+ maxLines: () => 'max-lines',
140
+ contain: () => 'contain',
141
+ verticalAlign: () => 'vertical-align',
142
+ clipping: (v) => {
143
+ if (v === false) {
144
+ return null;
145
+ }
146
+
147
+ return { prop: 'overflow', value: v ? 'hidden' : 'visible' };
148
+ },
149
+ rotation: (v) => {
150
+ if (v === 0) {
151
+ return null;
152
+ }
153
+
154
+ return { prop: 'transform', value: `rotate(${v}rad)` };
155
+ },
156
+ scale: (v) => {
157
+ if (v === 1) {
158
+ return null;
159
+ }
160
+
161
+ return { prop: 'transform', value: `scale(${v})` };
162
+ },
163
+ scaleX: (v) => {
164
+ if (v === 1) {
165
+ return null;
166
+ }
167
+
168
+ return { prop: 'transform', value: `scaleX(${v})` };
169
+ },
170
+ scaleY: (v) => {
171
+ if (v === 1) {
172
+ return null;
173
+ }
174
+
175
+ return { prop: 'transform', value: `scaleY(${v})` };
176
+ },
177
+ color: (v) => {
178
+ if (v === 0) {
179
+ return null;
180
+ }
181
+
182
+ return { prop: 'color', value: convertColorToRgba(v as number) };
183
+ },
184
+ };
185
+
186
+ const convertColorToRgba = (color: number) => {
187
+ const a = (color & 0xff) / 255;
188
+ const b = (color >> 8) & 0xff;
189
+ const g = (color >> 16) & 0xff;
190
+ const r = (color >> 24) & 0xff;
191
+ return `rgba(${r},${g},${b},${a})`;
192
+ };
193
+
194
+ const domPropertyMap: { [key: string]: string } = {
195
+ id: 'test-id',
196
+ };
197
+
198
+ const gradientColorPropertyMap = [
199
+ 'colorTop',
200
+ 'colorBottom',
201
+ 'colorLeft',
202
+ 'colorRight',
203
+ 'colorTl',
204
+ 'colorTr',
205
+ 'colorBl',
206
+ 'colorBr',
207
+ ];
208
+
209
+ const textureTypeNames: Record<number, string> = {
210
+ [TextureType.generic]: 'generic',
211
+ [TextureType.color]: 'color',
212
+ [TextureType.image]: 'image',
213
+ [TextureType.noise]: 'noise',
214
+ [TextureType.renderToTexture]: 'renderToTexture',
215
+ [TextureType.subTexture]: 'subTexture',
216
+ };
217
+
218
+ interface TextureMetrics {
219
+ previousState: string;
220
+ loadedCount: number;
221
+ failedCount: number;
222
+ freedCount: number;
223
+ }
224
+
225
+ const knownProperties = new Set<string>([
226
+ ...Object.keys(stylePropertyMap),
227
+ ...Object.keys(domPropertyMap),
228
+ // ...gradientColorPropertyMap,
229
+ 'src',
230
+ 'parent',
231
+ 'data',
232
+ 'text',
233
+ ]);
234
+
235
+ export class Inspector {
236
+ private root: HTMLElement | null = null;
237
+ private canvas: HTMLCanvasElement | null = null;
238
+ private mutationObserver: MutationObserver = new MutationObserver(() => {});
239
+ private resizeObserver: ResizeObserver = new ResizeObserver(() => {});
240
+ private height = 1080;
241
+ private width = 1920;
242
+ private scaleX = 1;
243
+ private scaleY = 1;
244
+ private textureMetrics = new Map<Texture, TextureMetrics>();
245
+
246
+ // Performance monitoring for frequent setter calls
247
+ private static setterCallCount = new Map<
248
+ string,
249
+ { count: number; lastReset: number; nodeId: number }
250
+ >();
251
+
252
+ // Animation monitoring structures
253
+ private static activeAnimations = new Map<
254
+ string,
255
+ {
256
+ nodeId: number;
257
+ animationId: string;
258
+ startTime: number;
259
+ props: CoreNodeAnimateProps;
260
+ settings: AnimationSettings;
261
+ controller: IAnimationController;
262
+ state: AnimationControllerState;
263
+ }
264
+ >();
265
+
266
+ private static animationHistory: Array<{
267
+ nodeId: number;
268
+ animationId: string;
269
+ startTime: number;
270
+ endTime: number;
271
+ duration: number;
272
+ actualDuration: number;
273
+ props: CoreNodeAnimateProps;
274
+ settings: AnimationSettings;
275
+ completionType: 'finished' | 'stopped' | 'cancelled';
276
+ }> = [];
277
+
278
+ // Performance monitoring settings (configured via constructor)
279
+ private performanceSettings: InspectorOptions = {
280
+ enablePerformanceMonitoring: false,
281
+ excessiveCallThreshold: 100,
282
+ resetInterval: 5000,
283
+ enableAnimationMonitoring: false,
284
+ maxAnimationHistory: 1000,
285
+ animationStatsInterval: 0,
286
+ };
287
+
288
+ // Animation stats printing timer
289
+ private animationStatsTimer: number | null = null;
290
+
291
+ constructor(canvas: HTMLCanvasElement, settings: RendererMainSettings) {
292
+ if (isProductionEnvironment === true) return;
293
+
294
+ if (!settings) {
295
+ throw new Error('settings is required');
296
+ }
297
+
298
+ // Initialize performance monitoring settings with defaults
299
+ this.performanceSettings = {
300
+ enablePerformanceMonitoring:
301
+ settings.inspectorOptions?.enablePerformanceMonitoring ?? false,
302
+ excessiveCallThreshold:
303
+ settings.inspectorOptions?.excessiveCallThreshold ?? 100,
304
+ resetInterval: settings.inspectorOptions?.resetInterval ?? 5000,
305
+ enableAnimationMonitoring:
306
+ settings.inspectorOptions?.enableAnimationMonitoring ?? false,
307
+ maxAnimationHistory:
308
+ settings.inspectorOptions?.maxAnimationHistory ?? 1000,
309
+ animationStatsInterval:
310
+ settings.inspectorOptions?.animationStatsInterval ?? 0,
311
+ };
312
+
313
+ // calc dimensions based on the devicePixelRatio
314
+ this.height = Math.ceil(
315
+ settings.appHeight ?? 1080 / (settings.deviceLogicalPixelRatio ?? 1),
316
+ );
317
+
318
+ this.width = Math.ceil(
319
+ settings.appWidth ?? 1920 / (settings.deviceLogicalPixelRatio ?? 1),
320
+ );
321
+
322
+ this.scaleX = settings.deviceLogicalPixelRatio ?? 1;
323
+ this.scaleY = settings.deviceLogicalPixelRatio ?? 1;
324
+
325
+ this.canvas = canvas;
326
+ this.root = document.createElement('div');
327
+ this.setRootPosition();
328
+ document.body.appendChild(this.root);
329
+
330
+ //listen for changes on canvas
331
+ this.mutationObserver = new MutationObserver(
332
+ this.setRootPosition.bind(this),
333
+ );
334
+ this.mutationObserver.observe(canvas, {
335
+ attributes: true,
336
+ childList: false,
337
+ subtree: false,
338
+ });
339
+
340
+ // Create a ResizeObserver to watch for changes in the element's size
341
+ this.resizeObserver = new ResizeObserver(this.setRootPosition.bind(this));
342
+ this.resizeObserver.observe(canvas);
343
+
344
+ //listen for changes on window
345
+ window.addEventListener('resize', this.setRootPosition.bind(this));
346
+
347
+ // Start animation stats timer if enabled
348
+ this.startAnimationStatsTimer();
349
+
350
+ console.warn('Inspector is enabled, this will impact performance');
351
+ }
352
+
353
+ /**
354
+ * Track setter calls for performance monitoring
355
+ * Only active when Inspector is loaded
356
+ */
357
+ private trackSetterCall(nodeId: number, setterName: string): void {
358
+ if (!this.performanceSettings.enablePerformanceMonitoring) {
359
+ return;
360
+ }
361
+
362
+ const key = `${nodeId}_${setterName}`;
363
+ const now = Date.now();
364
+ const existing = Inspector.setterCallCount.get(key);
365
+
366
+ if (!existing) {
367
+ Inspector.setterCallCount.set(key, { count: 1, lastReset: now, nodeId });
368
+ return;
369
+ }
370
+
371
+ // Reset counter if enough time has passed
372
+ if (now - existing.lastReset > this.performanceSettings.resetInterval) {
373
+ existing.count = 1;
374
+ existing.lastReset = now;
375
+ return;
376
+ }
377
+
378
+ existing.count++;
379
+
380
+ // Log if threshold exceeded
381
+ if (existing.count === this.performanceSettings.excessiveCallThreshold) {
382
+ console.warn(
383
+ `🚨 Inspector Performance Warning: Setter '${setterName}' called ${existing.count} times in ${this.performanceSettings.resetInterval}ms on node ${nodeId}`,
384
+ );
385
+ } else if (
386
+ existing.count > this.performanceSettings.excessiveCallThreshold &&
387
+ existing.count % 50 === 0
388
+ ) {
389
+ console.warn(
390
+ `🚨 Inspector Performance Warning: Setter '${setterName}' called ${existing.count} times in ${this.performanceSettings.resetInterval}ms on node ${nodeId} (continuing...)`,
391
+ );
392
+ }
393
+ }
394
+
395
+ /**
396
+ * Get current performance monitoring statistics
397
+ */
398
+ public static getPerformanceStats(): Array<{
399
+ nodeId: number;
400
+ setterName: string;
401
+ count: number;
402
+ timeWindow: number;
403
+ }> {
404
+ const stats: Array<{
405
+ nodeId: number;
406
+ setterName: string;
407
+ count: number;
408
+ timeWindow: number;
409
+ }> = [];
410
+ const now = Date.now();
411
+
412
+ Inspector.setterCallCount.forEach((data, key) => {
413
+ const parts = key.split('_');
414
+ const nodeIdStr = parts[0];
415
+ const setterName = parts[1];
416
+
417
+ if (nodeIdStr && setterName) {
418
+ const timeWindow = now - data.lastReset;
419
+
420
+ stats.push({
421
+ nodeId: parseInt(nodeIdStr, 10),
422
+ setterName,
423
+ count: data.count,
424
+ timeWindow,
425
+ });
426
+ }
427
+ });
428
+
429
+ return stats.sort((a, b) => b.count - a.count);
430
+ }
431
+
432
+ /**
433
+ * Clear performance monitoring statistics
434
+ */
435
+ public static clearPerformanceStats(): void {
436
+ Inspector.setterCallCount.clear();
437
+ }
438
+
439
+ /**
440
+ * Generate a unique animation ID
441
+ */
442
+ private static generateAnimationId(): string {
443
+ return `anim_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
444
+ }
445
+
446
+ /**
447
+ * Wrap animation controller with monitoring capabilities
448
+ */
449
+ private wrapAnimationController(
450
+ controller: IAnimationController,
451
+ nodeId: number,
452
+ props: CoreNodeAnimateProps,
453
+ settings: AnimationSettings,
454
+ div: HTMLElement,
455
+ ): IAnimationController {
456
+ if (!this.performanceSettings.enableAnimationMonitoring) {
457
+ // Just add the basic DOM animation without tracking
458
+ const originalStart = controller.start.bind(controller);
459
+ controller.start = () => {
460
+ this.animateNode(div, props, settings);
461
+ return originalStart();
462
+ };
463
+ return controller;
464
+ }
465
+
466
+ const animationId = Inspector.generateAnimationId();
467
+
468
+ // Create wrapper controller
469
+ const wrappedController: IAnimationController = {
470
+ start: () => {
471
+ this.trackAnimationStart(
472
+ animationId,
473
+ nodeId,
474
+ props,
475
+ settings,
476
+ controller,
477
+ );
478
+ this.animateNode(div, props, settings);
479
+ return controller.start();
480
+ },
481
+
482
+ stop: () => {
483
+ this.trackAnimationEnd(animationId, 'stopped');
484
+ return controller.stop();
485
+ },
486
+
487
+ pause: () => {
488
+ this.updateAnimationState(animationId, 'paused');
489
+ return controller.pause();
490
+ },
491
+
492
+ restore: () => {
493
+ this.trackAnimationEnd(animationId, 'cancelled');
494
+ return controller.restore();
495
+ },
496
+
497
+ waitUntilStopped: () => {
498
+ return controller.waitUntilStopped().then(() => {
499
+ this.trackAnimationEnd(animationId, 'finished');
500
+ });
501
+ },
502
+
503
+ get state() {
504
+ return controller.state;
505
+ },
506
+
507
+ // Event emitter methods
508
+ on: controller.on.bind(controller),
509
+ off: controller.off.bind(controller),
510
+ once: controller.once.bind(controller),
511
+ emit: controller.emit.bind(controller),
512
+ };
513
+
514
+ // Track animation events
515
+ controller.on('animating', () => {
516
+ this.updateAnimationState(animationId, 'running');
517
+ });
518
+
519
+ controller.on('stopped', () => {
520
+ this.trackAnimationEnd(animationId, 'finished');
521
+ });
522
+
523
+ return wrappedController;
524
+ }
525
+
526
+ /**
527
+ * Track animation start
528
+ */
529
+ private trackAnimationStart(
530
+ animationId: string,
531
+ nodeId: number,
532
+ props: CoreNodeAnimateProps,
533
+ settings: AnimationSettings,
534
+ controller: IAnimationController,
535
+ ): void {
536
+ const startTime = Date.now();
537
+
538
+ Inspector.activeAnimations.set(animationId, {
539
+ nodeId,
540
+ animationId,
541
+ startTime,
542
+ props,
543
+ settings,
544
+ controller,
545
+ state: 'scheduled',
546
+ });
547
+ }
548
+
549
+ /**
550
+ * Update animation state
551
+ */
552
+ private updateAnimationState(
553
+ animationId: string,
554
+ state: AnimationControllerState,
555
+ ): void {
556
+ const animation = Inspector.activeAnimations.get(animationId);
557
+ if (animation) {
558
+ animation.state = state;
559
+ }
560
+ }
561
+
562
+ /**
563
+ * Track animation end
564
+ */
565
+ private trackAnimationEnd(
566
+ animationId: string,
567
+ completionType: 'finished' | 'stopped' | 'cancelled',
568
+ ): void {
569
+ const animation = Inspector.activeAnimations.get(animationId);
570
+ if (!animation) return;
571
+
572
+ const endTime = Date.now();
573
+ const actualDuration = endTime - animation.startTime;
574
+ const expectedDuration = animation.settings.duration || 1000;
575
+
576
+ // Move to history
577
+ Inspector.animationHistory.unshift({
578
+ nodeId: animation.nodeId,
579
+ animationId: animation.animationId,
580
+ startTime: animation.startTime,
581
+ endTime,
582
+ duration: expectedDuration,
583
+ actualDuration,
584
+ props: animation.props,
585
+ settings: animation.settings,
586
+ completionType,
587
+ });
588
+
589
+ // Limit history size for performance
590
+ if (
591
+ Inspector.animationHistory.length >
592
+ this.performanceSettings.maxAnimationHistory
593
+ ) {
594
+ Inspector.animationHistory.splice(
595
+ this.performanceSettings.maxAnimationHistory,
596
+ );
597
+ }
598
+
599
+ // Remove from active animations
600
+ Inspector.activeAnimations.delete(animationId);
601
+ }
602
+
603
+ /**
604
+ * Get currently active animations
605
+ */
606
+ public static getActiveAnimations(): Array<{
607
+ nodeId: number;
608
+ animationId: string;
609
+ startTime: number;
610
+ duration: number;
611
+ elapsedTime: number;
612
+ props: CoreNodeAnimateProps;
613
+ settings: AnimationSettings;
614
+ state: AnimationControllerState;
615
+ }> {
616
+ const now = Date.now();
617
+ const activeAnimations: Array<{
618
+ nodeId: number;
619
+ animationId: string;
620
+ startTime: number;
621
+ duration: number;
622
+ elapsedTime: number;
623
+ props: CoreNodeAnimateProps;
624
+ settings: AnimationSettings;
625
+ state: AnimationControllerState;
626
+ }> = [];
627
+
628
+ Inspector.activeAnimations.forEach((animation) => {
629
+ activeAnimations.push({
630
+ nodeId: animation.nodeId,
631
+ animationId: animation.animationId,
632
+ startTime: animation.startTime,
633
+ duration: animation.settings.duration || 1000,
634
+ elapsedTime: now - animation.startTime,
635
+ props: animation.props,
636
+ settings: animation.settings,
637
+ state: animation.state,
638
+ });
639
+ });
640
+
641
+ return activeAnimations.sort((a, b) => b.startTime - a.startTime);
642
+ }
643
+
644
+ /**
645
+ * Get animation statistics
646
+ */
647
+ public static getAnimationStats(): {
648
+ totalAnimations: number;
649
+ activeCount: number;
650
+ averageDuration: number;
651
+ } {
652
+ const totalAnimations = Inspector.animationHistory.length;
653
+ const activeCount = Inspector.activeAnimations.size;
654
+
655
+ // Calculate average duration from finished animations only
656
+ const finishedAnimations = Inspector.animationHistory.filter(
657
+ (anim) => anim.completionType === 'finished',
658
+ );
659
+
660
+ const averageDuration =
661
+ finishedAnimations.length > 0
662
+ ? finishedAnimations.reduce(
663
+ (sum, anim) => sum + anim.actualDuration,
664
+ 0,
665
+ ) / finishedAnimations.length
666
+ : 0;
667
+
668
+ return {
669
+ totalAnimations,
670
+ activeCount,
671
+ averageDuration,
672
+ };
673
+ }
674
+
675
+ /**
676
+ * Clear animation monitoring data
677
+ */
678
+ public static clearAnimationStats(): void {
679
+ Inspector.activeAnimations.clear();
680
+ Inspector.animationHistory.length = 0;
681
+ }
682
+
683
+ /**
684
+ * Start the animation stats timer if enabled
685
+ */
686
+ private startAnimationStatsTimer(): void {
687
+ console.log(
688
+ `Starting animation stats timer with interval: ${this.performanceSettings.animationStatsInterval} seconds`,
689
+ );
690
+
691
+ if (this.performanceSettings.animationStatsInterval > 0) {
692
+ this.animationStatsTimer = setInterval(() => {
693
+ this.printAnimationStats();
694
+ }, this.performanceSettings.animationStatsInterval * 1000) as unknown as number;
695
+ }
696
+ }
697
+
698
+ /**
699
+ * Stop the animation stats timer
700
+ */
701
+ private stopAnimationStatsTimer(): void {
702
+ if (this.animationStatsTimer) {
703
+ clearInterval(this.animationStatsTimer);
704
+ this.animationStatsTimer = null;
705
+ }
706
+ }
707
+
708
+ /**
709
+ * Print current animation statistics to console
710
+ */
711
+ private printAnimationStats(): void {
712
+ const stats = Inspector.getAnimationStats();
713
+
714
+ console.log(
715
+ `🎬 Animation Stats: ${stats.activeCount} active, ${
716
+ stats.totalAnimations
717
+ } completed, ${Math.round(stats.averageDuration)}ms avg duration`,
718
+ );
719
+ }
720
+ setRootPosition() {
721
+ if (this.root === null || this.canvas === null) {
722
+ return;
723
+ }
724
+
725
+ // get the world position of the canvas object, so we can match the inspector to it
726
+ const rect = this.canvas.getBoundingClientRect();
727
+ const top = document.documentElement.scrollTop + rect.top;
728
+ const left = document.documentElement.scrollLeft + rect.left;
729
+
730
+ this.root.id = 'root';
731
+ this.root.style.left = `${left}px`;
732
+ this.root.style.top = `${top}px`;
733
+ this.root.style.width = `${this.width}px`;
734
+ this.root.style.height = `${this.height}px`;
735
+ this.root.style.position = 'absolute';
736
+ this.root.style.transformOrigin = '0 0 0';
737
+ this.root.style.transform = `scale(${this.scaleX}, ${this.scaleY})`;
738
+ this.root.style.overflow = 'hidden';
739
+ this.root.style.zIndex = '65534';
740
+ }
741
+
742
+ createDiv(
743
+ id: number,
744
+ properties: CoreNodeProps | CoreTextNodeProps,
745
+ ): HTMLElement {
746
+ const div = document.createElement('div');
747
+ div.style.position = 'absolute';
748
+ div.id = id.toString();
749
+
750
+ // set initial properties
751
+ for (const key in properties) {
752
+ this.updateNodeProperty(
753
+ div,
754
+ // really typescript? really?
755
+ key as keyof CoreNodeProps,
756
+ properties[key as keyof CoreNodeProps],
757
+ properties,
758
+ );
759
+ }
760
+
761
+ return div;
762
+ }
763
+
764
+ createNodes(node: CoreNode): boolean {
765
+ if (this.root === null) {
766
+ return false;
767
+ }
768
+
769
+ const div = this.root.querySelector(`[id="${node.id}"]`);
770
+ if (div === null && node instanceof CoreTextNode) {
771
+ this.createTextNode(node);
772
+ } else if (div === null && node instanceof CoreNode) {
773
+ this.createNode(node);
774
+ }
775
+
776
+ for (const child of node.children) {
777
+ this.createNodes(child);
778
+ }
779
+ return true;
780
+ }
781
+
782
+ createNode(node: CoreNode): CoreNode {
783
+ const div = this.createDiv(node.id, node.props);
784
+ (div as HTMLElement & { node: CoreNode }).node = node;
785
+ (node as CoreNode & { div: HTMLElement }).div = div;
786
+
787
+ node.on('inViewport', () => div.setAttribute('state', 'inViewport'));
788
+ node.on('inBounds', () => div.setAttribute('state', 'inBounds'));
789
+ node.on('outOfBounds', () => div.setAttribute('state', 'outOfBounds'));
790
+
791
+ // Monitor only relevant properties by trapping with selective assignment
792
+ return this.createProxy(node, div);
793
+ }
794
+
795
+ createTextNode(node: CoreTextNode): CoreTextNode {
796
+ // eslint-disable-next-line
797
+ // @ts-ignore - textProps is a private property and keeping it that way
798
+ // but we need it from the inspector to set the initial properties on the div element
799
+ const div = this.createDiv(node.id, node.textProps);
800
+ (div as HTMLElement & { node: CoreNode }).node = node;
801
+ (node as CoreTextNode & { div: HTMLElement }).div = div;
802
+
803
+ return this.createProxy(node, div) as CoreTextNode;
804
+ }
805
+
806
+ createProxy(
807
+ node: CoreNode | CoreTextNode,
808
+ div: HTMLElement,
809
+ ): CoreNode | CoreTextNode {
810
+ // Store texture event listeners for cleanup
811
+ const textureListeners = new Map<
812
+ Texture,
813
+ {
814
+ onLoaded: () => void;
815
+ onFailed: () => void;
816
+ onFreed: () => void;
817
+ }
818
+ >();
819
+
820
+ const coreNodeListeners = new Map<
821
+ CoreNode,
822
+ {
823
+ onLoaded: () => void;
824
+ }
825
+ >();
826
+
827
+ const setupCoreNodeListeners = (coreNode: CoreNode) => {
828
+ const onLoaded = () => {
829
+ this.updateTextNodeDimensions(div, coreNode as CoreTextNode);
830
+ };
831
+ coreNode.on('loaded', onLoaded);
832
+ coreNodeListeners.set(coreNode, { onLoaded });
833
+ };
834
+
835
+ // Helper function to setup texture event listeners
836
+ const setupTextureListeners = (texture: Texture | null) => {
837
+ // Clean up existing listeners first
838
+ textureListeners.forEach((listeners, oldTexture) => {
839
+ oldTexture.off('loaded', listeners.onLoaded);
840
+ oldTexture.off('failed', listeners.onFailed);
841
+ oldTexture.off('freed', listeners.onFreed);
842
+ });
843
+ textureListeners.clear();
844
+
845
+ // Setup new listeners if texture exists
846
+ if (texture) {
847
+ // Initialize metrics if not exists
848
+ if (!this.textureMetrics.has(texture)) {
849
+ this.textureMetrics.set(texture, {
850
+ previousState: texture.state,
851
+ loadedCount: 0,
852
+ failedCount: 0,
853
+ freedCount: 0,
854
+ });
855
+ }
856
+
857
+ const onLoaded = () => {
858
+ const metrics = this.textureMetrics.get(texture);
859
+ if (metrics) {
860
+ metrics.previousState =
861
+ metrics.previousState !== texture.state
862
+ ? metrics.previousState
863
+ : 'loading';
864
+ metrics.loadedCount++;
865
+ }
866
+ this.updateTextureAttributes(div, texture);
867
+ };
868
+ const onFailed = () => {
869
+ const metrics = this.textureMetrics.get(texture);
870
+ if (metrics) {
871
+ metrics.previousState =
872
+ metrics.previousState !== texture.state
873
+ ? metrics.previousState
874
+ : 'loading';
875
+ metrics.failedCount++;
876
+ }
877
+ this.updateTextureAttributes(div, texture);
878
+ };
879
+ const onFreed = () => {
880
+ const metrics = this.textureMetrics.get(texture);
881
+ if (metrics) {
882
+ metrics.previousState =
883
+ metrics.previousState !== texture.state
884
+ ? metrics.previousState
885
+ : texture.state;
886
+ metrics.freedCount++;
887
+ }
888
+ this.updateTextureAttributes(div, texture);
889
+ };
890
+
891
+ texture.on('loaded', onLoaded);
892
+ texture.on('failed', onFailed);
893
+ texture.on('freed', onFreed);
894
+
895
+ textureListeners.set(texture, { onLoaded, onFailed, onFreed });
896
+ }
897
+ };
898
+ // Define traps for each property in knownProperties
899
+ knownProperties.forEach((property) => {
900
+ let originalProp = Object.getOwnPropertyDescriptor(node, property);
901
+
902
+ if (originalProp === undefined) {
903
+ // Search the prototype chain for the property descriptor
904
+ const proto = Object.getPrototypeOf(node) as CoreNode | CoreTextNode;
905
+ originalProp = Object.getOwnPropertyDescriptor(proto, property);
906
+ }
907
+
908
+ if (originalProp === undefined) {
909
+ return;
910
+ }
911
+
912
+ if (property === 'text') {
913
+ setupCoreNodeListeners(node);
914
+ }
915
+
916
+ Object.defineProperty(node, property, {
917
+ get() {
918
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
919
+ return originalProp?.get?.call(node);
920
+ },
921
+ set: (value) => {
922
+ // Track setter call for performance monitoring
923
+ this.trackSetterCall(node.id, property);
924
+
925
+ originalProp?.set?.call(node, value);
926
+ this.updateNodeProperty(
927
+ div,
928
+ property as keyof CoreNodeProps | keyof CoreTextNodeProps,
929
+ value,
930
+ node.props,
931
+ );
932
+
933
+ // Setup texture event listeners if this is a texture property
934
+ if (property === 'texture') {
935
+ const textureValue =
936
+ value && typeof value === 'object' && 'state' in value
937
+ ? (value as Texture)
938
+ : null;
939
+ setupTextureListeners(textureValue);
940
+ }
941
+ },
942
+ configurable: true,
943
+ enumerable: true,
944
+ });
945
+ });
946
+
947
+ const originalDestroy = node.destroy;
948
+ Object.defineProperty(node, 'destroy', {
949
+ value: () => {
950
+ // Clean up texture event listeners and metrics
951
+ textureListeners.forEach((listeners, texture) => {
952
+ texture.off('loaded', listeners.onLoaded);
953
+ texture.off('failed', listeners.onFailed);
954
+ texture.off('freed', listeners.onFreed);
955
+ // Clean up metrics for this texture
956
+ this.textureMetrics.delete(texture);
957
+ });
958
+ textureListeners.clear();
959
+
960
+ coreNodeListeners.forEach((listeners, coreNode) => {
961
+ coreNode.off('loaded', listeners.onLoaded);
962
+ });
963
+ coreNodeListeners.clear();
964
+
965
+ this.destroyNode(node.id);
966
+ originalDestroy.call(node);
967
+ },
968
+ configurable: true,
969
+ });
970
+
971
+ const originalAnimate = node.animate;
972
+ Object.defineProperty(node, 'animate', {
973
+ value: (
974
+ props: CoreNodeAnimateProps,
975
+ settings: AnimationSettings,
976
+ ): IAnimationController => {
977
+ const animationController = originalAnimate.call(node, props, settings);
978
+
979
+ // Wrap animation controller with monitoring
980
+ return this.wrapAnimationController(
981
+ animationController,
982
+ node.id,
983
+ props,
984
+ settings,
985
+ div,
986
+ );
987
+ },
988
+ configurable: true,
989
+ });
990
+
991
+ return node;
992
+ }
993
+
994
+ updateTextNodeDimensions(div: HTMLElement, node: CoreTextNode) {
995
+ const textMetrics = node.renderInfo;
996
+ if (textMetrics) {
997
+ div.style.width = `${textMetrics.width}px`;
998
+ div.style.height = `${textMetrics.height}px`;
999
+ } else {
1000
+ div.style.removeProperty('width');
1001
+ div.style.removeProperty('height');
1002
+ }
1003
+ }
1004
+
1005
+ updateTextureAttributes(div: HTMLElement, texture: Texture) {
1006
+ // Update texture state
1007
+ div.setAttribute('data-texture-state', texture.state);
1008
+
1009
+ // Update texture type
1010
+ div.setAttribute(
1011
+ 'data-texture-type',
1012
+ textureTypeNames[texture.type] || 'unknown',
1013
+ );
1014
+
1015
+ // Update texture dimensions if available
1016
+ if (texture.dimensions) {
1017
+ div.setAttribute('data-texture-width', String(texture.dimensions.w));
1018
+ div.setAttribute('data-texture-height', String(texture.dimensions.h));
1019
+ } else {
1020
+ div.removeAttribute('data-texture-width');
1021
+ div.removeAttribute('data-texture-height');
1022
+ }
1023
+
1024
+ // Update renderable owners count
1025
+ div.setAttribute(
1026
+ 'data-texture-owners',
1027
+ String(texture.renderableOwners.length),
1028
+ );
1029
+
1030
+ // Update retry count
1031
+ div.setAttribute('data-texture-retry-count', String(texture.retryCount));
1032
+
1033
+ // Update max retry count if available
1034
+ if (texture.maxRetryCount !== null) {
1035
+ div.setAttribute(
1036
+ 'data-texture-max-retry-count',
1037
+ String(texture.maxRetryCount),
1038
+ );
1039
+ } else {
1040
+ div.removeAttribute('data-texture-max-retry-count');
1041
+ }
1042
+
1043
+ // Update metrics if available
1044
+ const metrics = this.textureMetrics.get(texture);
1045
+ if (metrics) {
1046
+ div.setAttribute('data-texture-previous-state', metrics.previousState);
1047
+ div.setAttribute(
1048
+ 'data-texture-loaded-count',
1049
+ String(metrics.loadedCount),
1050
+ );
1051
+ div.setAttribute(
1052
+ 'data-texture-failed-count',
1053
+ String(metrics.failedCount),
1054
+ );
1055
+ div.setAttribute('data-texture-freed-count', String(metrics.freedCount));
1056
+ } else {
1057
+ div.removeAttribute('data-texture-previous-state');
1058
+ div.removeAttribute('data-texture-loaded-count');
1059
+ div.removeAttribute('data-texture-failed-count');
1060
+ div.removeAttribute('data-texture-freed-count');
1061
+ }
1062
+
1063
+ // Update error information if present
1064
+ if (texture.error) {
1065
+ div.setAttribute(
1066
+ 'data-texture-error',
1067
+ texture.error.code || texture.error.message,
1068
+ );
1069
+ } else {
1070
+ div.removeAttribute('data-texture-error');
1071
+ }
1072
+ }
1073
+
1074
+ public destroy() {
1075
+ // Stop animation stats timer
1076
+ this.stopAnimationStatsTimer();
1077
+
1078
+ // Remove DOM observers
1079
+ this.mutationObserver.disconnect();
1080
+ this.resizeObserver.disconnect();
1081
+
1082
+ // Remove resize listener
1083
+ window.removeEventListener('resize', this.setRootPosition.bind(this));
1084
+ if (this.root && this.root.parentNode) {
1085
+ this.root.remove();
1086
+ }
1087
+
1088
+ // Clean up animation monitoring data
1089
+ Inspector.clearAnimationStats();
1090
+ }
1091
+
1092
+ destroyNode(id: number) {
1093
+ const div = document.getElementById(id.toString());
1094
+ div?.remove();
1095
+ }
1096
+
1097
+ updateNodeProperty(
1098
+ div: HTMLElement,
1099
+ property: keyof CoreNodeProps | keyof CoreTextNodeProps,
1100
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1101
+ value: any,
1102
+ props: CoreNodeProps | CoreTextNodeProps,
1103
+ ) {
1104
+ if (this.root === null || value === undefined || value === null) {
1105
+ return;
1106
+ }
1107
+
1108
+ /**
1109
+ * Special case for parent property
1110
+ */
1111
+ if (property === 'parent') {
1112
+ const parentId: number = value.id;
1113
+
1114
+ // only way to detect if the parent is the root node
1115
+ // if you are reading this and have a better way, please let me know
1116
+ if (parentId === 1) {
1117
+ this.root.appendChild(div);
1118
+ return;
1119
+ }
1120
+
1121
+ const parent = document.getElementById(parentId.toString());
1122
+ parent?.appendChild(div);
1123
+ return;
1124
+ }
1125
+
1126
+ // special case for text
1127
+ if (property === 'text') {
1128
+ div.innerHTML = String(value);
1129
+
1130
+ // Keep DOM text invisible without breaking visibility checks
1131
+ // Use very low opacity (0.001) instead of 0 so Playwright still detects it
1132
+ div.style.opacity = '0.001';
1133
+ div.style.pointerEvents = 'none';
1134
+ div.style.userSelect = 'none';
1135
+ return;
1136
+ }
1137
+
1138
+ // special case for images
1139
+ // we're not setting any CSS properties to avoid images getting loaded twice
1140
+ // as the renderer will handle the loading of the image. Setting it to `data-src`
1141
+ if (property === 'src' && value) {
1142
+ div.setAttribute(`data-src`, String(value));
1143
+ return;
1144
+ }
1145
+
1146
+ // special case for color gradients (normal colors are handled by the stylePropertyMap)
1147
+ // FIXME the renderer seems to return the same number for all colors
1148
+ // if (gradientColorPropertyMap.includes(property as string)) {
1149
+ // const color = convertColorToRgba(value as number);
1150
+ // div.setAttribute(`data-${property}`, color);
1151
+ // return;
1152
+ // }
1153
+
1154
+ if (property === 'rtt' && value) {
1155
+ div.setAttribute('data-rtt', String(value));
1156
+ return;
1157
+ }
1158
+
1159
+ // CSS mappable attribute
1160
+ if (stylePropertyMap[property]) {
1161
+ const mappedStyleResponse = stylePropertyMap[property]?.(value);
1162
+
1163
+ if (mappedStyleResponse === null) {
1164
+ return;
1165
+ }
1166
+
1167
+ if (typeof mappedStyleResponse === 'string') {
1168
+ div.style.setProperty(mappedStyleResponse, String(value));
1169
+ return;
1170
+ }
1171
+
1172
+ if (typeof mappedStyleResponse === 'object') {
1173
+ let value = mappedStyleResponse.value;
1174
+ if (property === 'x') {
1175
+ const mount = props.mountX;
1176
+ const width = props.w;
1177
+
1178
+ if (mount) {
1179
+ value = `${parseInt(value) - width * mount}px`;
1180
+ }
1181
+ } else if (property === 'y') {
1182
+ const mount = props.mountY;
1183
+ const height = props.h;
1184
+
1185
+ if (mount) {
1186
+ value = `${parseInt(value) - height * mount}px`;
1187
+ }
1188
+ }
1189
+ div.style.setProperty(mappedStyleResponse.prop, value);
1190
+ }
1191
+
1192
+ return;
1193
+ }
1194
+
1195
+ // DOM properties
1196
+ if (domPropertyMap[property]) {
1197
+ const domProperty = domPropertyMap[property];
1198
+ if (!domProperty) {
1199
+ return;
1200
+ }
1201
+
1202
+ div.setAttribute(String(domProperty), String(value));
1203
+ return;
1204
+ }
1205
+
1206
+ // custom data properties
1207
+ if (property === 'data') {
1208
+ for (const key in value) {
1209
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1210
+ const keyValue: unknown = value[key];
1211
+ if (keyValue === undefined) {
1212
+ div.removeAttribute(`data-${key}`);
1213
+ } else {
1214
+ div.setAttribute(`data-${key}`, String(keyValue));
1215
+ }
1216
+ }
1217
+ return;
1218
+ }
1219
+ }
1220
+
1221
+ updateViewport(
1222
+ width: number,
1223
+ height: number,
1224
+ deviceLogicalPixelRatio: number,
1225
+ ) {
1226
+ this.scaleX = deviceLogicalPixelRatio ?? 1;
1227
+ this.scaleY = deviceLogicalPixelRatio ?? 1;
1228
+
1229
+ this.width = width;
1230
+ this.height = height;
1231
+ this.setRootPosition();
1232
+ }
1233
+
1234
+ // simple animation handler
1235
+ animateNode(
1236
+ div: HTMLElement,
1237
+ props: CoreNodeAnimateProps,
1238
+ settings: AnimationSettings,
1239
+ ) {
1240
+ const {
1241
+ duration = 1000,
1242
+ delay = 0,
1243
+ // easing = 'linear',
1244
+ // repeat = 0,
1245
+ // loop = false,
1246
+ // stopMethod = false,
1247
+ } = settings;
1248
+
1249
+ const {
1250
+ x,
1251
+ y,
1252
+ w,
1253
+ h,
1254
+ alpha = 1,
1255
+ rotation = 0,
1256
+ scale = 1,
1257
+ color,
1258
+ mountX,
1259
+ mountY,
1260
+ } = props;
1261
+
1262
+ // ignoring loops and repeats for now, as that might be a bit too much for the inspector
1263
+ function animate() {
1264
+ setTimeout(() => {
1265
+ div.style.top = `${y - h * mountY}px`;
1266
+ div.style.left = `${x - w * mountX}px`;
1267
+ div.style.width = `${w}px`;
1268
+ div.style.height = `${h}px`;
1269
+ div.style.opacity = `${alpha}`;
1270
+ div.style.rotate = `${rotation}rad`;
1271
+ div.style.scale = `${scale}`;
1272
+ div.style.color = convertColorToRgba(color);
1273
+ }, duration);
1274
+ }
1275
+
1276
+ setTimeout(animate, delay);
1277
+ }
1278
+ }