@lightningjs/renderer 3.0.3 → 3.0.5

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 (240) hide show
  1. package/dist/src/common/EventEmitter.d.ts +7 -4
  2. package/dist/src/common/EventEmitter.js +1 -1
  3. package/dist/src/common/EventEmitter.js.map +1 -1
  4. package/dist/src/core/AutosizeManager.d.ts +29 -0
  5. package/dist/src/core/AutosizeManager.js +169 -0
  6. package/dist/src/core/AutosizeManager.js.map +1 -0
  7. package/dist/src/core/CoreNode.d.ts +2 -1
  8. package/dist/src/core/CoreNode.js +6 -3
  9. package/dist/src/core/CoreNode.js.map +1 -1
  10. package/dist/src/core/CoreTextNode.d.ts +18 -5
  11. package/dist/src/core/CoreTextNode.js +141 -59
  12. package/dist/src/core/CoreTextNode.js.map +1 -1
  13. package/dist/src/core/CoreTextNodeCanvas.d.ts +215 -0
  14. package/dist/src/core/CoreTextNodeCanvas.js +236 -0
  15. package/dist/src/core/CoreTextNodeCanvas.js.map +1 -0
  16. package/dist/src/core/Stage.js +10 -0
  17. package/dist/src/core/Stage.js.map +1 -1
  18. package/dist/src/core/TextureMemoryManager.js +4 -3
  19. package/dist/src/core/TextureMemoryManager.js.map +1 -1
  20. package/dist/src/core/animations/Animation.d.ts +21 -0
  21. package/dist/src/core/animations/Animation.js +194 -0
  22. package/dist/src/core/animations/Animation.js.map +1 -0
  23. package/dist/src/core/animations/AnimationManager.d.ts +1 -1
  24. package/dist/src/core/animations/AnimationManager.js +5 -5
  25. package/dist/src/core/animations/AnimationManager.js.map +1 -1
  26. package/dist/src/core/animations/CoreAnimation.d.ts +11 -2
  27. package/dist/src/core/animations/CoreAnimation.js +44 -38
  28. package/dist/src/core/animations/CoreAnimation.js.map +1 -1
  29. package/dist/src/core/animations/CoreAnimationController.d.ts +6 -0
  30. package/dist/src/core/animations/CoreAnimationController.js +16 -3
  31. package/dist/src/core/animations/CoreAnimationController.js.map +1 -1
  32. package/dist/src/core/animations/Playback.d.ts +64 -0
  33. package/dist/src/core/animations/Playback.js +169 -0
  34. package/dist/src/core/animations/Playback.js.map +1 -0
  35. package/dist/src/core/animations/Ticker.d.ts +71 -0
  36. package/dist/src/core/animations/Ticker.js +89 -0
  37. package/dist/src/core/animations/Ticker.js.map +1 -0
  38. package/dist/src/core/animations/Transition.d.ts +38 -0
  39. package/dist/src/core/animations/Transition.js +35 -0
  40. package/dist/src/core/animations/Transition.js.map +1 -0
  41. package/dist/src/core/animations/TransitionsController.d.ts +10 -0
  42. package/dist/src/core/animations/TransitionsController.js +39 -0
  43. package/dist/src/core/animations/TransitionsController.js.map +1 -0
  44. package/dist/src/core/animations/utils.d.ts +2 -0
  45. package/dist/src/core/animations/utils.js +136 -0
  46. package/dist/src/core/animations/utils.js.map +1 -0
  47. package/dist/src/core/lib/ImageWorker.d.ts +2 -2
  48. package/dist/src/core/lib/ImageWorker.js +11 -30
  49. package/dist/src/core/lib/ImageWorker.js.map +1 -1
  50. package/dist/src/core/lib/WebGlContextWrapper.d.ts +5 -16
  51. package/dist/src/core/lib/WebGlContextWrapper.js +1 -35
  52. package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -1
  53. package/dist/src/core/lib/textureCompression.d.ts +2 -14
  54. package/dist/src/core/lib/textureCompression.js +67 -320
  55. package/dist/src/core/lib/textureCompression.js.map +1 -1
  56. package/dist/src/core/platform.js +9 -38
  57. package/dist/src/core/platform.js.map +1 -1
  58. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.d.ts +0 -1
  59. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.js +3 -11
  60. package/dist/src/core/renderers/canvas/CanvasCoreRenderer.js.map +1 -1
  61. package/dist/src/core/renderers/canvas/CanvasCoreTexture.d.ts +1 -2
  62. package/dist/src/core/renderers/canvas/CanvasCoreTexture.js +11 -16
  63. package/dist/src/core/renderers/canvas/CanvasCoreTexture.js.map +1 -1
  64. package/dist/src/core/renderers/canvas/CanvasRenderer.js +14 -1
  65. package/dist/src/core/renderers/canvas/CanvasRenderer.js.map +1 -1
  66. package/dist/src/core/renderers/canvas/CanvasTexture.d.ts +1 -1
  67. package/dist/src/core/renderers/canvas/CanvasTexture.js +16 -6
  68. package/dist/src/core/renderers/canvas/CanvasTexture.js.map +1 -1
  69. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.d.ts +0 -13
  70. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.js +192 -113
  71. package/dist/src/core/renderers/canvas/internal/C2DShaderUtils.js.map +1 -1
  72. package/dist/src/core/renderers/canvas/internal/ColorUtils.d.ts +2 -0
  73. package/dist/src/core/renderers/canvas/internal/ColorUtils.js +14 -0
  74. package/dist/src/core/renderers/canvas/internal/ColorUtils.js.map +1 -1
  75. package/dist/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.d.ts +1 -2
  76. package/dist/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.js +5 -12
  77. package/dist/src/core/renderers/webgl/WebGlCoreCtxRenderTexture.js.map +1 -1
  78. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.d.ts +6 -18
  79. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +60 -102
  80. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
  81. package/dist/src/core/renderers/webgl/WebGlCoreRenderOp.js +1 -1
  82. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.d.ts +1 -3
  83. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +31 -74
  84. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
  85. package/dist/src/core/renderers/webgl/WebGlCoreShader.d.ts +7 -2
  86. package/dist/src/core/renderers/webgl/WebGlCoreShader.js +50 -21
  87. package/dist/src/core/renderers/webgl/WebGlCoreShader.js.map +1 -1
  88. package/dist/src/core/renderers/webgl/WebGlRenderOp.d.ts +2 -3
  89. package/dist/src/core/renderers/webgl/WebGlRenderOp.js +1 -3
  90. package/dist/src/core/renderers/webgl/WebGlRenderOp.js.map +1 -1
  91. package/dist/src/core/renderers/webgl/WebGlRenderer.d.ts +2 -2
  92. package/dist/src/core/renderers/webgl/WebGlRenderer.js.map +1 -1
  93. package/dist/src/core/renderers/webgl/WebGlShaderNode.d.ts +1 -0
  94. package/dist/src/core/renderers/webgl/WebGlShaderNode.js +23 -0
  95. package/dist/src/core/renderers/webgl/WebGlShaderNode.js.map +1 -1
  96. package/dist/src/core/renderers/webgl/WebGlShaderProgram.js +4 -5
  97. package/dist/src/core/renderers/webgl/WebGlShaderProgram.js.map +1 -1
  98. package/dist/src/core/renderers/webgl/internal/ShaderUtils.d.ts +1 -0
  99. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js.map +1 -1
  100. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js +6 -3
  101. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js.map +1 -1
  102. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js +11 -0
  103. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js.map +1 -1
  104. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js +10 -5
  105. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js.map +1 -1
  106. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js +10 -5
  107. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js.map +1 -1
  108. package/dist/src/core/renderers/webgl/shaders/SdfShader.js +12 -0
  109. package/dist/src/core/renderers/webgl/shaders/SdfShader.js.map +1 -1
  110. package/dist/src/core/renderers/webgl/shaders/effects/BorderBottomEffect.js +1 -1
  111. package/dist/src/core/renderers/webgl/shaders/effects/BorderLeftEffect.js +1 -1
  112. package/dist/src/core/renderers/webgl/shaders/effects/BorderRightEffect.js +1 -1
  113. package/dist/src/core/renderers/webgl/shaders/effects/BorderTopEffect.js +1 -1
  114. package/dist/src/core/renderers/webgl/shaders/effects/EffectUtils.js +2 -2
  115. package/dist/src/core/renderers/webgl/shaders/effects/FadeOutEffect.js +5 -5
  116. package/dist/src/core/renderers/webgl/shaders/effects/HolePunchEffect.js +1 -1
  117. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.d.ts +1 -0
  118. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js +30 -14
  119. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js.map +1 -1
  120. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.d.ts +0 -1
  121. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js +3 -13
  122. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js.map +1 -1
  123. package/dist/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.js +1 -1
  124. package/dist/src/core/renderers/webgl/shaders/effects/RadiusEffect.js +5 -5
  125. package/dist/src/core/shaders/webgl/SdfShadowShader.d.ts +9 -0
  126. package/dist/src/core/shaders/webgl/SdfShadowShader.js +100 -0
  127. package/dist/src/core/shaders/webgl/SdfShadowShader.js.map +1 -0
  128. package/dist/src/core/text-rendering/CanvasFont.d.ts +1 -1
  129. package/dist/src/core/text-rendering/CanvasFont.js +7 -16
  130. package/dist/src/core/text-rendering/CanvasFont.js.map +1 -1
  131. package/dist/src/core/text-rendering/CanvasFontHandler.d.ts +1 -1
  132. package/dist/src/core/text-rendering/CanvasFontHandler.js +1 -1
  133. package/dist/src/core/text-rendering/CanvasFontHandler.js.map +1 -1
  134. package/dist/src/core/text-rendering/CanvasTextRenderer.d.ts +2 -3
  135. package/dist/src/core/text-rendering/CanvasTextRenderer.js +7 -5
  136. package/dist/src/core/text-rendering/CanvasTextRenderer.js.map +1 -1
  137. package/dist/src/core/text-rendering/CoreFont.d.ts +1 -1
  138. package/dist/src/core/text-rendering/CoreFont.js +1 -1
  139. package/dist/src/core/text-rendering/CoreFont.js.map +1 -1
  140. package/dist/src/core/text-rendering/FontManager.js +2 -1
  141. package/dist/src/core/text-rendering/FontManager.js.map +1 -1
  142. package/dist/src/core/text-rendering/SdfTextRenderer.d.ts +3 -5
  143. package/dist/src/core/text-rendering/SdfTextRenderer.js +19 -109
  144. package/dist/src/core/text-rendering/SdfTextRenderer.js.map +1 -1
  145. package/dist/src/core/text-rendering/TextLayoutEngine.js +43 -12
  146. package/dist/src/core/text-rendering/TextLayoutEngine.js.map +1 -1
  147. package/dist/src/core/text-rendering/TextRenderer.d.ts +16 -8
  148. package/dist/src/core/text-rendering/canvas/Settings.d.ts +64 -0
  149. package/dist/src/core/text-rendering/canvas/Settings.js +20 -0
  150. package/dist/src/core/text-rendering/canvas/Settings.js.map +1 -0
  151. package/dist/src/core/text-rendering/canvas/Utils.d.ts +20 -0
  152. package/dist/src/core/text-rendering/canvas/Utils.js +144 -0
  153. package/dist/src/core/text-rendering/canvas/Utils.js.map +1 -0
  154. package/dist/src/core/text-rendering/canvas/calculateRenderInfo.d.ts +60 -0
  155. package/dist/src/core/text-rendering/canvas/calculateRenderInfo.js +183 -0
  156. package/dist/src/core/text-rendering/canvas/calculateRenderInfo.js.map +1 -0
  157. package/dist/src/core/text-rendering/canvas/draw.d.ts +5 -0
  158. package/dist/src/core/text-rendering/canvas/draw.js +132 -0
  159. package/dist/src/core/text-rendering/canvas/draw.js.map +1 -0
  160. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js +2 -2
  161. package/dist/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.js.map +1 -1
  162. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +3 -4
  163. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +46 -98
  164. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
  165. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.d.ts +1 -1
  166. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.d.ts +2 -2
  167. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js +66 -8
  168. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.js.map +1 -1
  169. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.d.ts +1 -1
  170. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +1 -1
  171. package/dist/src/core/text-rendering/renderers/canvas/CanvasTextRenderer.d.ts +26 -0
  172. package/dist/src/core/text-rendering/renderers/canvas/CanvasTextRenderer.js +158 -0
  173. package/dist/src/core/text-rendering/renderers/canvas/CanvasTextRenderer.js.map +1 -0
  174. package/dist/src/core/text-rendering/renderers/canvas/internal/draw.d.ts +5 -0
  175. package/dist/src/core/text-rendering/renderers/canvas/internal/draw.js +127 -0
  176. package/dist/src/core/text-rendering/renderers/canvas/internal/draw.js.map +1 -0
  177. package/dist/src/core/text-rendering/renderers/canvas/internal/mergeDefaults.d.ts +2 -0
  178. package/dist/src/core/text-rendering/renderers/canvas/internal/mergeDefaults.js +50 -0
  179. package/dist/src/core/text-rendering/renderers/canvas/internal/mergeDefaults.js.map +1 -0
  180. package/dist/src/core/text-rendering/renderers/canvas/internal/renderInfo.d.ts +33 -0
  181. package/dist/src/core/text-rendering/renderers/canvas/internal/renderInfo.js +192 -0
  182. package/dist/src/core/text-rendering/renderers/canvas/internal/renderInfo.js.map +1 -0
  183. package/dist/src/core/text-rendering/renderers/canvas/internal/types.d.ts +66 -0
  184. package/dist/src/core/text-rendering/renderers/canvas/internal/types.js +2 -0
  185. package/dist/src/core/text-rendering/renderers/canvas/internal/types.js.map +1 -0
  186. package/dist/src/core/text-rendering/renderers/canvas/internal/utils.d.ts +91 -0
  187. package/dist/src/core/text-rendering/renderers/canvas/internal/utils.js +282 -0
  188. package/dist/src/core/text-rendering/renderers/canvas/internal/utils.js.map +1 -0
  189. package/dist/src/core/text-rendering/sdf/PeekableGenerator.d.ts +12 -0
  190. package/dist/src/core/text-rendering/sdf/PeekableGenerator.js +61 -0
  191. package/dist/src/core/text-rendering/sdf/PeekableGenerator.js.map +1 -0
  192. package/dist/src/core/text-rendering/sdf/SimpleFontShaper.d.ts +45 -0
  193. package/dist/src/core/text-rendering/sdf/SimpleFontShaper.js +69 -0
  194. package/dist/src/core/text-rendering/sdf/SimpleFontShaper.js.map +1 -0
  195. package/dist/src/core/text-rendering/sdf/Utils.d.ts +26 -0
  196. package/dist/src/core/text-rendering/sdf/Utils.js +301 -0
  197. package/dist/src/core/text-rendering/sdf/Utils.js.map +1 -0
  198. package/dist/src/core/text-rendering/sdf/index.d.ts +1 -0
  199. package/dist/src/core/text-rendering/sdf/index.js +20 -0
  200. package/dist/src/core/text-rendering/sdf/index.js.map +1 -0
  201. package/dist/src/core/textures/ImageTexture.js +11 -0
  202. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  203. package/dist/src/core/textures/Texture.js +5 -0
  204. package/dist/src/core/textures/Texture.js.map +1 -1
  205. package/dist/src/main-api/Inspector.d.ts +1 -1
  206. package/dist/src/main-api/Inspector.js +25 -20
  207. package/dist/src/main-api/Inspector.js.map +1 -1
  208. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  209. package/dist/tsconfig.tsbuildinfo +1 -0
  210. package/package.json +1 -1
  211. package/src/common/EventEmitter.ts +6 -8
  212. package/src/core/CoreNode.test.ts +1 -1
  213. package/src/core/CoreNode.ts +8 -4
  214. package/src/core/CoreTextNode.test.ts +138 -25
  215. package/src/core/CoreTextNode.ts +174 -67
  216. package/src/core/Stage.ts +11 -0
  217. package/src/core/TextureMemoryManager.ts +4 -3
  218. package/src/core/animations/AnimationManager.ts +5 -5
  219. package/src/core/animations/CoreAnimation.ts +61 -45
  220. package/src/core/animations/CoreAnimationController.ts +16 -7
  221. package/src/core/renderers/canvas/CanvasRenderer.ts +19 -1
  222. package/src/core/renderers/canvas/CanvasTexture.ts +23 -8
  223. package/src/core/renderers/webgl/WebGlRenderer.ts +2 -3
  224. package/src/core/renderers/webgl/WebGlShaderNode.ts +24 -0
  225. package/src/core/renderers/webgl/WebGlShaderProgram.test.ts +274 -0
  226. package/src/core/renderers/webgl/WebGlShaderProgram.ts +10 -10
  227. package/src/core/renderers/webgl/internal/ShaderUtils.ts +1 -0
  228. package/src/core/text-rendering/CanvasFontHandler.ts +2 -2
  229. package/src/core/text-rendering/CanvasTextRenderer.ts +14 -7
  230. package/src/core/text-rendering/SdfTextRenderer.ts +28 -140
  231. package/src/core/text-rendering/TextLayoutEngine.ts +61 -28
  232. package/src/core/text-rendering/TextRenderer.ts +19 -12
  233. package/src/core/text-rendering/tests/TextLayoutEngine.test.ts +20 -0
  234. package/src/core/textures/ImageTexture.ts +18 -0
  235. package/src/core/textures/Texture.ts +6 -0
  236. package/src/main-api/Inspector.ts +25 -25
  237. package/dist/src/core/text-rendering/TextGenerator.d.ts +0 -10
  238. package/dist/src/core/text-rendering/TextGenerator.js +0 -36
  239. package/dist/src/core/text-rendering/TextGenerator.js.map +0 -1
  240. package/src/core/renderers/webgl/SdfRenderOp.ts +0 -106
@@ -0,0 +1,274 @@
1
+ /*
2
+ * If not stated otherwise in this file or this component's LICENSE file the
3
+ * following copyright and licenses apply:
4
+ *
5
+ * Copyright 2026 Comcast Cable Communications Management, LLC.
6
+ *
7
+ * Licensed under the Apache License, Version 2.0 (the License);
8
+ * you may not use this file except in compliance with the License.
9
+ * You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+
20
+ import { describe, expect, it, vi } from 'vitest';
21
+ import { mock } from 'vitest-mock-extended';
22
+ import { CoreTextNode, type CoreTextNodeProps } from '../../CoreTextNode.js';
23
+ import type { Stage } from '../../Stage.js';
24
+ import type { TextRenderer } from '../../text-rendering/TextRenderer.js';
25
+ import { createBound } from '../../lib/utils.js';
26
+ import type { CoreRenderer } from '../CoreRenderer.js';
27
+ import { WebGlRenderer } from './WebGlRenderer.js';
28
+ import { WebGlShaderProgram } from './WebGlShaderProgram.js';
29
+
30
+ const makeStage = (): Stage =>
31
+ mock<Stage>({
32
+ strictBound: createBound(0, 0, 1920, 1080),
33
+ preloadBound: createBound(0, 0, 1920, 1080),
34
+ defaultTexture: {
35
+ state: 'loaded',
36
+ },
37
+ pixelRatio: 2,
38
+ renderer: mock<CoreRenderer>() as CoreRenderer,
39
+ });
40
+
41
+ const makeTextProps = (): CoreTextNodeProps => ({
42
+ alpha: 1,
43
+ autosize: false,
44
+ boundsMargin: null,
45
+ clipping: false,
46
+ color: 0xffffffff,
47
+ colorBl: 0xffffffff,
48
+ colorBottom: 0xffffffff,
49
+ colorBr: 0xffffffff,
50
+ colorLeft: 0xffffffff,
51
+ colorRight: 0xffffffff,
52
+ colorTl: 0xffffffff,
53
+ colorTop: 0xffffffff,
54
+ colorTr: 0xffffffff,
55
+ h: 20,
56
+ mount: 0,
57
+ mountX: 0,
58
+ mountY: 0,
59
+ parent: null,
60
+ pivot: 0,
61
+ pivotX: 0,
62
+ pivotY: 0,
63
+ rotation: 0,
64
+ rtt: false,
65
+ scale: 1,
66
+ scaleX: 1,
67
+ scaleY: 1,
68
+ shader: null,
69
+ src: '',
70
+ texture: null,
71
+ textureOptions: {},
72
+ w: 100,
73
+ x: 0,
74
+ y: 0,
75
+ zIndex: 0,
76
+ text: 'Test',
77
+ textAlign: 'left',
78
+ contain: 'none',
79
+ fontFamily: 'Arial',
80
+ fontStyle: 'normal',
81
+ fontSize: 16,
82
+ letterSpacing: 0,
83
+ lineHeight: 1,
84
+ maxHeight: 0,
85
+ maxLines: 0,
86
+ maxWidth: 0,
87
+ offsetY: 0,
88
+ overflowSuffix: '...',
89
+ verticalAlign: 'top',
90
+ wordBreak: 'break-word',
91
+ textRendererOverride: null,
92
+ forceLoad: false,
93
+ });
94
+
95
+ const makeSdfTextRenderer = (): TextRenderer =>
96
+ ({
97
+ clearCache: vi.fn(),
98
+ type: 'sdf',
99
+ font: {
100
+ isFontLoaded: vi.fn().mockReturnValue(true),
101
+ loadFont: vi.fn(),
102
+ waitingForFont: vi.fn(),
103
+ stopWaitingForFont: vi.fn(),
104
+ },
105
+ init: vi.fn(),
106
+ renderText: vi.fn().mockReturnValue({
107
+ width: 100,
108
+ height: 20,
109
+ layout: { glyphs: [], width: 100, height: 20 },
110
+ }),
111
+ addQuads: vi.fn().mockReturnValue(new Float32Array(0)),
112
+ renderQuads: vi.fn(),
113
+ } as unknown as TextRenderer);
114
+
115
+ const makeSdfTextNode = () => {
116
+ const node = new CoreTextNode(
117
+ makeStage(),
118
+ makeTextProps(),
119
+ makeSdfTextRenderer(),
120
+ );
121
+ node.parentHasRenderTexture = true;
122
+ node.framebufferDimensions = { w: 320, h: 180 };
123
+ node.rttParent = { framebufferDimensions: { w: 640, h: 360 } } as any;
124
+ return node;
125
+ };
126
+
127
+ describe('WebGlShaderProgram.bindRenderOp', () => {
128
+ function createProgram() {
129
+ const program = Object.create(
130
+ WebGlShaderProgram.prototype,
131
+ ) as WebGlShaderProgram;
132
+ const bindTextures = vi.fn();
133
+ const bindBufferCollection = vi.fn();
134
+ const uniform1f = vi.fn();
135
+ const uniform2f = vi.fn();
136
+ const glw = {
137
+ canvas: { width: 1920, height: 1080 },
138
+ uniform1f,
139
+ uniform2f,
140
+ };
141
+
142
+ (program as any).bindTextures = bindTextures;
143
+ (program as any).bindBufferCollection = bindBufferCollection;
144
+ (program as any).glw = glw;
145
+ (program as any).useTimeValue = false;
146
+ (program as any).useSystemAlpha = false;
147
+ (program as any).useSystemDimensions = false;
148
+
149
+ return {
150
+ program,
151
+ bindTextures,
152
+ bindBufferCollection,
153
+ uniform1f,
154
+ uniform2f,
155
+ };
156
+ }
157
+
158
+ it('binds SDF shader props while using the main framebuffer resolution', () => {
159
+ const {
160
+ program,
161
+ bindTextures,
162
+ bindBufferCollection,
163
+ uniform1f,
164
+ uniform2f,
165
+ } = createProgram();
166
+ const onSdfBind = vi.fn();
167
+ const renderOp = {
168
+ isCoreNode: false,
169
+ isSdfRenderOp: true,
170
+ shader: { shaderType: { onSdfBind } },
171
+ sdfShaderProps: { size: 16, distanceRange: 4 },
172
+ renderOpTextures: [],
173
+ quadBufferCollection: {},
174
+ parentHasRenderTexture: false,
175
+ framebufferDimensions: null,
176
+ rtt: false,
177
+ stage: { pixelRatio: 1.5 },
178
+ time: 0,
179
+ worldAlpha: 1,
180
+ w: 100,
181
+ h: 20,
182
+ };
183
+
184
+ program.bindRenderOp(renderOp as any);
185
+
186
+ expect(bindTextures).toHaveBeenCalledWith(renderOp.renderOpTextures);
187
+ expect(bindBufferCollection).toHaveBeenCalledWith(
188
+ renderOp.quadBufferCollection,
189
+ );
190
+ expect(uniform1f).toHaveBeenCalledWith('u_pixelRatio', 1.5);
191
+ expect(uniform2f).toHaveBeenCalledWith('u_resolution', 1920, 1080);
192
+ expect(onSdfBind).toHaveBeenCalledWith(renderOp.sdfShaderProps);
193
+ });
194
+
195
+ it('keeps SDF binding active when rendering into a parent framebuffer', () => {
196
+ const { program, uniform1f, uniform2f } = createProgram();
197
+ const onSdfBind = vi.fn();
198
+ const renderOp = {
199
+ isCoreNode: false,
200
+ isSdfRenderOp: true,
201
+ shader: { shaderType: { onSdfBind } },
202
+ sdfShaderProps: { size: 18, distanceRange: 6 },
203
+ renderOpTextures: [],
204
+ quadBufferCollection: {},
205
+ parentHasRenderTexture: true,
206
+ framebufferDimensions: { w: 320, h: 180 },
207
+ rtt: false,
208
+ stage: { pixelRatio: 2 },
209
+ time: 0,
210
+ worldAlpha: 1,
211
+ w: 100,
212
+ h: 20,
213
+ };
214
+
215
+ program.bindRenderOp(renderOp as any);
216
+
217
+ expect(uniform1f).toHaveBeenCalledWith('u_pixelRatio', 1);
218
+ expect(uniform2f).toHaveBeenCalledWith('u_resolution', 320, 180);
219
+ expect(onSdfBind).toHaveBeenCalledWith(renderOp.sdfShaderProps);
220
+ });
221
+
222
+ it('uses parent RTT dimensions for SDF text render ops', () => {
223
+ const { program, uniform1f, uniform2f } = createProgram();
224
+ const onSdfBind = vi.fn();
225
+ const sdfShaderProps = {
226
+ color: 0xffffffff,
227
+ distanceRange: 1,
228
+ size: 16,
229
+ transform: new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]),
230
+ };
231
+ const renderOp = {
232
+ framebufferDimensions: { w: 320, h: 180 },
233
+ isCoreNode: true,
234
+ isSdfRenderOp: true,
235
+ parentFramebufferDimensions: { w: 640, h: 360 },
236
+ parentHasRenderTexture: true,
237
+ quadBufferCollection: {},
238
+ renderOpTextures: [],
239
+ rtt: false,
240
+ sdfShaderProps,
241
+ shader: {
242
+ shaderType: {
243
+ onSdfBind,
244
+ },
245
+ },
246
+ stage: { pixelRatio: 2 },
247
+ time: 0,
248
+ worldAlpha: 1,
249
+ w: 100,
250
+ h: 20,
251
+ } as any;
252
+
253
+ program.bindRenderOp(renderOp);
254
+
255
+ expect(uniform1f).toHaveBeenCalledWith('u_pixelRatio', 1.0);
256
+ expect(uniform2f).toHaveBeenCalledWith('u_resolution', 640, 360);
257
+ expect(onSdfBind).toHaveBeenCalledWith(sdfShaderProps);
258
+ });
259
+ });
260
+
261
+ describe('WebGlRenderer.canReuseRenderOp', () => {
262
+ it('reuses SDF text render ops with matching parent RTT dimensions', () => {
263
+ const renderer = Object.create(WebGlRenderer.prototype) as WebGlRenderer;
264
+ const node = makeSdfTextNode();
265
+
266
+ node.props.shader = {
267
+ shaderKey: 'default',
268
+ } as any;
269
+
270
+ renderer.curRenderOp = node;
271
+
272
+ expect(renderer.reuseRenderOp(node)).toBe(true);
273
+ });
274
+ });
@@ -33,6 +33,8 @@ import {
33
33
  type UniformSet4Params,
34
34
  } from './internal/ShaderUtils.js';
35
35
  import { CoreNode } from '../../CoreNode.js';
36
+ import type { CoreTextNode } from '../../CoreTextNode.js';
37
+ import type { SdfShaderProps } from '../../shaders/webgl/SdfShader.js';
36
38
 
37
39
  export class WebGlShaderProgram implements CoreShaderProgram {
38
40
  protected program: WebGLProgram | null;
@@ -200,13 +202,11 @@ export class WebGlShaderProgram implements CoreShaderProgram {
200
202
  }
201
203
 
202
204
  bindRenderOp(renderOp: WebGlRenderOp) {
203
- const isCoreNode = renderOp.isCoreNode;
204
-
205
205
  this.bindTextures(renderOp.renderOpTextures);
206
206
  this.bindBufferCollection(renderOp.quadBufferCollection);
207
207
 
208
208
  const parentHasRenderTexture = renderOp.parentHasRenderTexture;
209
- const framebufferDimensions = isCoreNode
209
+ const framebufferDimensions = renderOp.isCoreNode
210
210
  ? renderOp.parentFramebufferDimensions
211
211
  : renderOp.framebufferDimensions;
212
212
 
@@ -248,22 +248,22 @@ export class WebGlShaderProgram implements CoreShaderProgram {
248
248
  }
249
249
 
250
250
  /**temporary fix to make sdf texts work */
251
- if (isCoreNode === false && renderOp.sdfShaderProps !== undefined) {
252
- const opShader = renderOp.shader; // SdfRenderOp has .shader
253
- (opShader.shaderType as WebGlShaderType).onSdfBind?.call(
251
+ if (renderOp.isSdfRenderOp === true) {
252
+ const opShader = renderOp.shader!; // SdfRenderOp has .shader
253
+ (opShader.shaderType as WebGlShaderType<SdfShaderProps>).onSdfBind?.call(
254
254
  this.glw,
255
- renderOp.sdfShaderProps,
255
+ (renderOp as CoreTextNode).sdfShaderProps,
256
256
  );
257
257
  return;
258
258
  }
259
259
 
260
260
  const shader = renderOp.shader as WebGlShaderNode;
261
- if (shader.props !== undefined) {
261
+ const uniforms = shader.uniforms;
262
+
263
+ if (uniforms.hasStoredUniforms === true) {
262
264
  /**
263
265
  * loop over all precalculated uniform types
264
266
  */
265
- const uniforms = shader.uniforms;
266
-
267
267
  for (const key in uniforms.single) {
268
268
  const { method, value } = uniforms.single[key]!;
269
269
  this.glw[method as keyof UniformSet1Param](key, value as never);
@@ -42,6 +42,7 @@ export type Vec4 = [number, number, number, number];
42
42
  export type UniformValue = SingleValue | Vec2 | Vec3 | Vec4;
43
43
 
44
44
  export interface UniformCollection {
45
+ hasStoredUniforms: boolean;
45
46
  single: Record<string, Uniform<SingleValue>>;
46
47
  vec2: Record<string, Uniform<Vec2>>;
47
48
  vec3: Record<string, Uniform<Vec3>>;
@@ -136,7 +136,7 @@ export const getFontFamilies = (): FontFamilyMap => {
136
136
  */
137
137
  export const init = (
138
138
  c: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
139
- mc: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
139
+ mc?: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
140
140
  ): void => {
141
141
  if (initialized === true) {
142
142
  return;
@@ -149,7 +149,7 @@ export const init = (
149
149
  }
150
150
 
151
151
  context = c;
152
- measureContext = mc;
152
+ measureContext = mc || c;
153
153
 
154
154
  // Register the default 'sans-serif' font face
155
155
  const defaultMetrics: FontMetrics = {
@@ -19,7 +19,12 @@
19
19
 
20
20
  import { assertTruthy } from '../../utils.js';
21
21
  import type { Stage } from '../Stage.js';
22
- import type { TextLineStruct, TextRenderInfo } from './TextRenderer.js';
22
+ import type {
23
+ CanvasRenderInfo,
24
+ FontHandler,
25
+ TextLineStruct,
26
+ TextRenderInfo,
27
+ } from './TextRenderer.js';
23
28
  import * as CanvasFontHandler from './CanvasFontHandler.js';
24
29
  import type { CoreTextNodeProps } from '../CoreTextNode.js';
25
30
  import { getLayoutCacheKey, hasZeroWidthSpace } from './Utils.js';
@@ -28,6 +33,7 @@ import { mapTextLayout } from './TextLayoutEngine.js';
28
33
  const MAX_TEXTURE_DIMENSION = 4096;
29
34
 
30
35
  const type = 'canvas' as const;
36
+ const font: FontHandler = CanvasFontHandler;
31
37
 
32
38
  let canvas: HTMLCanvasElement | OffscreenCanvas | null = null;
33
39
  let context:
@@ -43,7 +49,7 @@ let measureContext:
43
49
  | null = null;
44
50
 
45
51
  // Cache for text layout calculations
46
- const layoutCache = new Map<string, TextRenderInfo>();
52
+ const renderInfoCache = new Map<string, CanvasRenderInfo>();
47
53
 
48
54
  // Initialize the Text Renderer
49
55
  const init = (stage: Stage): void => {
@@ -89,7 +95,7 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
89
95
  assertTruthy(measureContext, 'Canvas measureContext is not available');
90
96
  const cacheKey = getLayoutCacheKey(props);
91
97
 
92
- let layout = layoutCache.get(cacheKey);
98
+ let layout = renderInfoCache.get(cacheKey);
93
99
  if (layout !== undefined) {
94
100
  return layout;
95
101
  }
@@ -187,13 +193,14 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
187
193
  imageData = context.getImageData(0, 0, canvasW, canvasH);
188
194
  }
189
195
  const renderInfo = {
196
+ type,
190
197
  imageData,
191
198
  width: effectiveWidth,
192
199
  height: effectiveHeight,
193
200
  remainingLines,
194
201
  hasRemainingText,
195
- };
196
- layoutCache.set(cacheKey, renderInfo);
202
+ } as CanvasRenderInfo;
203
+ renderInfoCache.set(cacheKey, renderInfo);
197
204
  return renderInfo;
198
205
  };
199
206
 
@@ -201,7 +208,7 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
201
208
  * Clear layout cache for memory management
202
209
  */
203
210
  const clearCache = (): void => {
204
- layoutCache.clear();
211
+ renderInfoCache.clear();
205
212
  };
206
213
 
207
214
  /**
@@ -217,7 +224,7 @@ const renderQuads = (): void => {
217
224
  */
218
225
  const CanvasTextRenderer = {
219
226
  type,
220
- font: CanvasFontHandler,
227
+ font,
221
228
  renderText,
222
229
  renderQuads,
223
230
  init,
@@ -20,23 +20,19 @@
20
20
  import type { Stage } from '../Stage.js';
21
21
  import type {
22
22
  FontHandler,
23
+ SdfRenderInfo,
23
24
  TextLineStruct,
24
25
  TextRenderInfo,
25
- TextRenderProps,
26
26
  } from './TextRenderer.js';
27
- import type { CoreTextNodeProps } from '../CoreTextNode.js';
27
+ import type { CoreTextNode, CoreTextNodeProps } from '../CoreTextNode.js';
28
28
  import { getLayoutCacheKey, hasZeroWidthSpace } from './Utils.js';
29
29
  import * as SdfFontHandler from './SdfFontHandler.js';
30
- import type { CoreRenderer } from '../renderers/CoreRenderer.js';
31
30
  import { WebGlRenderer } from '../renderers/webgl/WebGlRenderer.js';
32
- import { SdfRenderOp } from '../renderers/webgl/SdfRenderOp.js';
33
- import { Sdf, type SdfShaderProps } from '../shaders/webgl/SdfShader.js';
34
- import { BufferCollection } from '../renderers/webgl/internal/BufferCollection.js';
35
- import type { WebGlCtxTexture } from '../renderers/webgl/WebGlCtxTexture.js';
31
+ import { Sdf } from '../shaders/webgl/SdfShader.js';
36
32
  import type { WebGlShaderNode } from '../renderers/webgl/WebGlShaderNode.js';
37
- import { mergeColorAlpha } from '../../utils.js';
38
33
  import type { TextLayout } from './TextRenderer.js';
39
34
  import { mapTextLayout } from './TextLayoutEngine.js';
35
+ import type { WebGlCtxTexture } from '../renderers/webgl/WebGlCtxTexture.js';
40
36
 
41
37
  // Each glyph requires 6 vertices (2 triangles) with 4 floats each (x, y, u, v)
42
38
  const FLOATS_PER_VERTEX = 4;
@@ -46,6 +42,7 @@ const VERTICES_PER_GLYPH = 6;
46
42
  const type = 'sdf' as const;
47
43
 
48
44
  let sdfShader: WebGlShaderNode | null = null;
45
+ let renderer: WebGlRenderer | null = null;
49
46
 
50
47
  // Initialize the SDF text renderer
51
48
  const init = (stage: Stage): void => {
@@ -54,10 +51,11 @@ const init = (stage: Stage): void => {
54
51
  // Register SDF shader with the shader manager
55
52
  stage.shManager.registerShaderType('Sdf', Sdf);
56
53
  sdfShader = stage.shManager.createShader('Sdf') as WebGlShaderNode;
54
+ renderer = stage.renderer as WebGlRenderer;
57
55
  };
58
56
 
59
57
  const font: FontHandler = SdfFontHandler;
60
- const layoutCache = new Map<string, TextLayout>();
58
+ const renderInfoCache = new Map<string, SdfRenderInfo>();
61
59
 
62
60
  /**
63
61
  * SDF text renderer using MSDF/SDF fonts with WebGL
@@ -67,151 +65,41 @@ const layoutCache = new Map<string, TextLayout>();
67
65
  * @returns Object containing ImageData and dimensions
68
66
  */
69
67
  const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
70
- // Early return if no text
71
- if (props.text.length === 0) {
72
- return {
73
- width: 0,
74
- height: 0,
75
- };
76
- }
77
-
78
68
  const cacheKey = getLayoutCacheKey(props);
79
69
 
80
- let layout = layoutCache.get(cacheKey);
81
- if (layout !== undefined) {
82
- return {
83
- width: layout.width,
84
- height: layout.height,
85
- remainingLines: layout.remainingLines,
86
- hasRemainingText: layout.hasRemainingText,
87
- layout, // Cache layout for addQuads
88
- };
89
- }
90
-
91
- // Get font cache for this font family
92
- const fontData = SdfFontHandler.getFontData(props.fontFamily);
93
- if (fontData === undefined) {
94
- // Font not loaded, return empty result
95
- return {
96
- width: 0,
97
- height: 0,
98
- };
70
+ let renderInfo = renderInfoCache.get(cacheKey);
71
+ if (renderInfo !== undefined) {
72
+ return renderInfo;
99
73
  }
100
74
 
101
75
  // Calculate text layout and generate glyph data for caching
102
- layout = generateTextLayout(props, fontData);
103
- layoutCache.set(cacheKey, layout);
104
-
105
- // For SDF renderer, ImageData is null since we render via WebGL
106
- return {
76
+ const layout = generateTextLayout(
77
+ props,
78
+ SdfFontHandler.getFontData(props.fontFamily)!,
79
+ );
80
+ renderInfo = {
81
+ type,
82
+ layout,
107
83
  width: layout.width,
108
84
  height: layout.height,
109
85
  remainingLines: layout.remainingLines,
110
86
  hasRemainingText: layout.hasRemainingText,
111
- layout, // Cache layout for addQuads
112
- };
87
+ atlasTexture: SdfFontHandler.getAtlas(props.fontFamily)!
88
+ .ctxTexture as WebGlCtxTexture,
89
+ } as SdfRenderInfo;
90
+ renderInfoCache.set(cacheKey, renderInfo);
91
+
92
+ // For SDF renderer, ImageData is null since we render via WebGL
93
+ return renderInfo;
113
94
  };
114
95
 
115
96
  /**
116
97
  * Create and submit WebGL render operations for SDF text
117
98
  * This is called from CoreTextNode during rendering to add SDF text to the render pipeline
118
99
  */
119
- const renderQuads = (
120
- renderer: CoreRenderer,
121
- layout: TextLayout,
122
- renderProps: TextRenderProps,
123
- ): void => {
124
- const fontFamily = renderProps.fontFamily;
125
- const color = renderProps.color;
126
- const worldAlpha = renderProps.worldAlpha;
127
- const globalTransform = renderProps.globalTransform;
128
- const vertexBuffer = layout.vertexBuffer;
129
-
130
- const atlasTexture = SdfFontHandler.getAtlas(fontFamily);
131
- if (atlasTexture === null) {
132
- console.warn(`SDF atlas texture not found for font: ${fontFamily}`);
133
- return;
134
- }
135
-
136
- // We can safely assume this is a WebGL renderer else this wouldn't be called
137
- const glw = (renderer as WebGlRenderer).glw;
138
- const stride = 4 * Float32Array.BYTES_PER_ELEMENT;
139
-
140
- /**
141
- * Wraps a WebGLBuffer in a BufferCollection with the standard SDF vertex
142
- * layout, creates and submits an SdfRenderOp. Called by both the cache-miss
143
- * and cache-hit paths so attribute/op setup only exists in one place.
144
- */
145
- const buildAndSubmitRenderOp = (gpuBuffer: WebGLBuffer): void => {
146
- const webGlBuffers = new BufferCollection([
147
- {
148
- buffer: gpuBuffer,
149
- attributes: {
150
- a_position: {
151
- name: 'a_position',
152
- size: 2,
153
- type: glw.FLOAT as number,
154
- normalized: false,
155
- stride,
156
- offset: 0,
157
- },
158
- a_textureCoords: {
159
- name: 'a_textureCoords',
160
- size: 2,
161
- type: glw.FLOAT as number,
162
- normalized: false,
163
- stride,
164
- offset: 2 * Float32Array.BYTES_PER_ELEMENT,
165
- },
166
- },
167
- },
168
- ]);
169
-
170
- const renderOp = new SdfRenderOp(
171
- renderer as WebGlRenderer,
172
- sdfShader!,
173
- {
174
- transform: globalTransform,
175
- color: mergeColorAlpha(color, worldAlpha),
176
- size: layout.fontScale,
177
- distanceRange: layout.distanceRange,
178
- } satisfies SdfShaderProps,
179
- webGlBuffers,
180
- worldAlpha,
181
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
182
- renderProps.clippingRect as any,
183
- layout.width,
184
- layout.height,
185
- false,
186
- renderProps.parentHasRenderTexture,
187
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
188
- renderProps.framebufferDimensions as any,
189
- );
190
-
191
- renderOp.addTexture(atlasTexture.ctxTexture as WebGlCtxTexture);
192
- renderOp.numQuads = layout.glyphCount;
193
- (renderer as WebGlRenderer).addRenderOp(renderOp);
194
- };
195
-
196
- // Reuse the cached WebGLBuffer if one was provided — avoids a createBuffer
197
- // call every frame on nodes whose text has not changed.
198
- const glBufferRefBox = renderProps.glBufferRef;
199
-
200
- if (glBufferRefBox.current === null) {
201
- // Cache miss: allocate a new buffer, upload vertex data, then cache it.
202
- const newBuffer = glw.createBuffer() as WebGLBuffer | null;
203
- if (newBuffer === null) {
204
- console.warn('Failed to create WebGL buffer for SDF text');
205
- return;
206
- }
207
- // Upload vertex data directly into the new buffer.
208
- glw.arrayBufferData(newBuffer, vertexBuffer, glw.STATIC_DRAW as number);
209
- // Write back into the ref box so the owning node can reuse it next frame.
210
- glBufferRefBox.current = newBuffer;
211
- }
212
-
213
- // Cache hit (or freshly allocated): build the render op and submit.
214
- buildAndSubmitRenderOp(glBufferRefBox.current);
100
+ const renderQuads = (textNode: CoreTextNode): void => {
101
+ textNode.props.shader = sdfShader;
102
+ renderer!.addRenderOp(textNode);
215
103
  };
216
104
 
217
105
  /**
@@ -388,7 +276,7 @@ const generateTextLayout = (
388
276
  };
389
277
 
390
278
  const clearCache = (): void => {
391
- layoutCache.clear();
279
+ renderInfoCache.clear();
392
280
  };
393
281
 
394
282
  /**