@lightningjs/renderer 3.0.0-beta22 → 3.0.0-beta23

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 (166) hide show
  1. package/README.md +93 -0
  2. package/dist/exports/platform.d.ts +7 -0
  3. package/dist/exports/platform.js +27 -0
  4. package/dist/exports/platform.js.map +1 -0
  5. package/dist/src/core/AutosizeManager.d.ts +29 -0
  6. package/dist/src/core/AutosizeManager.js +169 -0
  7. package/dist/src/core/AutosizeManager.js.map +1 -0
  8. package/dist/src/core/CoreNode.js +10 -14
  9. package/dist/src/core/CoreNode.js.map +1 -1
  10. package/dist/src/core/CoreTextureManager.d.ts +0 -13
  11. package/dist/src/core/CoreTextureManager.js +4 -78
  12. package/dist/src/core/CoreTextureManager.js.map +1 -1
  13. package/dist/src/core/Stage.js +2 -12
  14. package/dist/src/core/Stage.js.map +1 -1
  15. package/dist/src/core/animations/Animation.d.ts +21 -0
  16. package/dist/src/core/animations/Animation.js +194 -0
  17. package/dist/src/core/animations/Animation.js.map +1 -0
  18. package/dist/src/core/animations/CoreAnimationController.d.ts +1 -1
  19. package/dist/src/core/animations/CoreAnimationController.js +4 -2
  20. package/dist/src/core/animations/CoreAnimationController.js.map +1 -1
  21. package/dist/src/core/animations/Playback.d.ts +64 -0
  22. package/dist/src/core/animations/Playback.js +169 -0
  23. package/dist/src/core/animations/Playback.js.map +1 -0
  24. package/dist/src/core/animations/Transition.d.ts +27 -0
  25. package/dist/src/core/animations/Transition.js +52 -0
  26. package/dist/src/core/animations/Transition.js.map +1 -0
  27. package/dist/src/core/animations/utils.d.ts +2 -0
  28. package/dist/src/core/animations/utils.js +136 -0
  29. package/dist/src/core/animations/utils.js.map +1 -0
  30. package/dist/src/core/lib/collectionUtils.js +3 -2
  31. package/dist/src/core/lib/collectionUtils.js.map +1 -1
  32. package/dist/src/core/lib/utils.d.ts +0 -5
  33. package/dist/src/core/lib/utils.js +0 -63
  34. package/dist/src/core/lib/utils.js.map +1 -1
  35. package/dist/src/core/platforms/GlContextWrapper.d.ts +136 -0
  36. package/dist/src/core/platforms/GlContextWrapper.js +32 -0
  37. package/dist/src/core/platforms/GlContextWrapper.js.map +1 -0
  38. package/dist/src/core/platforms/Platform.d.ts +74 -13
  39. package/dist/src/core/platforms/Platform.js +18 -0
  40. package/dist/src/core/platforms/Platform.js.map +1 -1
  41. package/dist/src/core/platforms/web/WebGlContextWrapper.d.ts +776 -0
  42. package/dist/src/core/platforms/web/WebGlContextWrapper.js +1208 -0
  43. package/dist/src/core/platforms/web/WebGlContextWrapper.js.map +1 -0
  44. package/dist/src/core/platforms/web/WebPlatform.d.ts +13 -2
  45. package/dist/src/core/platforms/web/WebPlatform.js +109 -8
  46. package/dist/src/core/platforms/web/WebPlatform.js.map +1 -1
  47. package/dist/src/core/platforms/web/WebPlatformChrome50.d.ts +17 -0
  48. package/dist/src/core/platforms/web/WebPlatformChrome50.js +50 -0
  49. package/dist/src/core/platforms/web/WebPlatformChrome50.js.map +1 -0
  50. package/dist/src/core/platforms/web/WebPlatformLegacy.d.ts +18 -0
  51. package/dist/src/core/platforms/web/WebPlatformLegacy.js +99 -0
  52. package/dist/src/core/platforms/web/WebPlatformLegacy.js.map +1 -0
  53. package/dist/src/core/platforms/web/WebPlatformNext.d.ts +21 -0
  54. package/dist/src/core/platforms/web/WebPlatformNext.js +52 -0
  55. package/dist/src/core/platforms/web/WebPlatformNext.js.map +1 -0
  56. package/dist/src/core/platforms/web/lib/ImageWorker.d.ts +15 -0
  57. package/dist/src/core/platforms/web/lib/ImageWorker.js +189 -0
  58. package/dist/src/core/platforms/web/lib/ImageWorker.js.map +1 -0
  59. package/dist/src/core/platforms/web/lib/createImageBitmap.d.ts +1 -0
  60. package/dist/src/core/platforms/web/lib/createImageBitmap.js +27 -0
  61. package/dist/src/core/platforms/web/lib/createImageBitmap.js.map +1 -0
  62. package/dist/src/core/platforms/web/lib/textureCompression.d.ts +26 -0
  63. package/dist/src/core/platforms/web/lib/textureCompression.js +301 -0
  64. package/dist/src/core/platforms/web/lib/textureCompression.js.map +1 -0
  65. package/dist/src/core/platforms/web/lib/textureSvg.d.ts +7 -0
  66. package/dist/src/core/platforms/web/lib/textureSvg.js +51 -0
  67. package/dist/src/core/platforms/web/lib/textureSvg.js.map +1 -0
  68. package/dist/src/core/platforms/web/lib/utils.d.ts +5 -0
  69. package/dist/src/core/platforms/web/lib/utils.js +86 -0
  70. package/dist/src/core/platforms/web/lib/utils.js.map +1 -0
  71. package/dist/src/core/renderers/CoreRenderer.d.ts +1 -9
  72. package/dist/src/core/renderers/CoreRenderer.js +2 -4
  73. package/dist/src/core/renderers/CoreRenderer.js.map +1 -1
  74. package/dist/src/core/renderers/canvas/CanvasRenderer.d.ts +3 -2
  75. package/dist/src/core/renderers/canvas/CanvasRenderer.js +4 -3
  76. package/dist/src/core/renderers/canvas/CanvasRenderer.js.map +1 -1
  77. package/dist/src/core/renderers/webgl/SdfRenderOp.js +3 -2
  78. package/dist/src/core/renderers/webgl/SdfRenderOp.js.map +1 -1
  79. package/dist/src/core/renderers/webgl/WebGlCtxRenderTexture.d.ts +2 -2
  80. package/dist/src/core/renderers/webgl/WebGlCtxRenderTexture.js.map +1 -1
  81. package/dist/src/core/renderers/webgl/WebGlCtxSubTexture.d.ts +2 -2
  82. package/dist/src/core/renderers/webgl/WebGlCtxSubTexture.js.map +1 -1
  83. package/dist/src/core/renderers/webgl/WebGlCtxTexture.d.ts +3 -3
  84. package/dist/src/core/renderers/webgl/WebGlCtxTexture.js +1 -2
  85. package/dist/src/core/renderers/webgl/WebGlCtxTexture.js.map +1 -1
  86. package/dist/src/core/renderers/webgl/WebGlRenderer.d.ts +5 -5
  87. package/dist/src/core/renderers/webgl/WebGlRenderer.js +7 -8
  88. package/dist/src/core/renderers/webgl/WebGlRenderer.js.map +1 -1
  89. package/dist/src/core/renderers/webgl/WebGlShaderNode.d.ts +2 -2
  90. package/dist/src/core/renderers/webgl/WebGlShaderProgram.d.ts +2 -2
  91. package/dist/src/core/renderers/webgl/WebGlShaderProgram.js.map +1 -1
  92. package/dist/src/core/renderers/webgl/internal/RendererUtils.d.ts +4 -4
  93. package/dist/src/core/renderers/webgl/internal/RendererUtils.js.map +1 -1
  94. package/dist/src/core/renderers/webgl/internal/ShaderUtils.d.ts +3 -3
  95. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js.map +1 -1
  96. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js +24 -8
  97. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js.map +1 -1
  98. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js +25 -8
  99. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js.map +1 -1
  100. package/dist/src/core/shaders/webgl/Border.js +6 -4
  101. package/dist/src/core/shaders/webgl/Border.js.map +1 -1
  102. package/dist/src/core/shaders/webgl/RoundedWithBorder.js +6 -4
  103. package/dist/src/core/shaders/webgl/RoundedWithBorder.js.map +1 -1
  104. package/dist/src/core/shaders/webgl/RoundedWithBorderAndShadow.js +6 -4
  105. package/dist/src/core/shaders/webgl/RoundedWithBorderAndShadow.js.map +1 -1
  106. package/dist/src/core/shaders/webgl/SdfShadowShader.d.ts +9 -0
  107. package/dist/src/core/shaders/webgl/SdfShadowShader.js +100 -0
  108. package/dist/src/core/shaders/webgl/SdfShadowShader.js.map +1 -0
  109. package/dist/src/core/text-rendering/CanvasFont.d.ts +1 -1
  110. package/dist/src/core/text-rendering/CanvasFont.js +2 -6
  111. package/dist/src/core/text-rendering/CanvasFont.js.map +1 -1
  112. package/dist/src/core/text-rendering/CoreFont.d.ts +1 -1
  113. package/dist/src/core/text-rendering/CoreFont.js +1 -1
  114. package/dist/src/core/text-rendering/CoreFont.js.map +1 -1
  115. package/dist/src/core/text-rendering/FontManager.js +2 -1
  116. package/dist/src/core/text-rendering/FontManager.js.map +1 -1
  117. package/dist/src/core/textures/ImageTexture.d.ts +24 -11
  118. package/dist/src/core/textures/ImageTexture.js +32 -95
  119. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  120. package/dist/src/core/textures/Texture.d.ts +1 -1
  121. package/dist/src/main-api/Renderer.js +18 -21
  122. package/dist/src/main-api/Renderer.js.map +1 -1
  123. package/dist/src/utils.d.ts +0 -2
  124. package/dist/src/utils.js +0 -36
  125. package/dist/src/utils.js.map +1 -1
  126. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  127. package/dist/tsconfig.tsbuildinfo +1 -0
  128. package/exports/platform.ts +31 -0
  129. package/package.json +3 -2
  130. package/src/core/CoreNode.ts +11 -15
  131. package/src/core/CoreTextureManager.ts +10 -103
  132. package/src/core/Stage.ts +1 -14
  133. package/src/core/animations/CoreAnimationController.ts +5 -2
  134. package/src/core/lib/collectionUtils.ts +3 -2
  135. package/src/core/lib/utils.ts +0 -78
  136. package/src/core/platforms/GlContextWrapper.ts +291 -0
  137. package/src/core/platforms/Platform.ts +121 -28
  138. package/src/core/{lib → platforms/web}/WebGlContextWrapper.ts +129 -4
  139. package/src/core/platforms/web/WebPlatform.ts +171 -22
  140. package/src/core/platforms/web/WebPlatformChrome50.ts +57 -0
  141. package/src/core/platforms/web/WebPlatformLegacy.ts +140 -0
  142. package/src/core/platforms/web/WebPlatformNext.ts +57 -0
  143. package/src/core/{lib → platforms/web/lib}/ImageWorker.ts +10 -74
  144. package/src/core/platforms/web/lib/createImageBitmap.ts +40 -0
  145. package/src/core/{lib → platforms/web/lib}/textureCompression.ts +19 -138
  146. package/src/core/{lib → platforms/web/lib}/textureSvg.ts +3 -15
  147. package/src/core/platforms/web/lib/utils.ts +105 -0
  148. package/src/core/renderers/CoreRenderer.ts +2 -11
  149. package/src/core/renderers/canvas/CanvasRenderer.ts +6 -4
  150. package/src/core/renderers/webgl/SdfRenderOp.ts +3 -2
  151. package/src/core/renderers/webgl/WebGlCtxRenderTexture.ts +2 -2
  152. package/src/core/renderers/webgl/WebGlCtxSubTexture.ts +2 -2
  153. package/src/core/renderers/webgl/WebGlCtxTexture.ts +3 -4
  154. package/src/core/renderers/webgl/WebGlRenderer.ts +12 -19
  155. package/src/core/renderers/webgl/WebGlShaderNode.ts +2 -2
  156. package/src/core/renderers/webgl/WebGlShaderProgram.ts +2 -2
  157. package/src/core/renderers/webgl/internal/RendererUtils.ts +4 -8
  158. package/src/core/renderers/webgl/internal/ShaderUtils.ts +3 -3
  159. package/src/core/shaders/webgl/Border.ts +6 -4
  160. package/src/core/shaders/webgl/RoundedWithBorder.ts +6 -4
  161. package/src/core/shaders/webgl/RoundedWithBorderAndShadow.ts +6 -4
  162. package/src/core/textures/ImageTexture.ts +42 -161
  163. package/src/core/textures/Texture.ts +1 -1
  164. package/src/main-api/Renderer.ts +24 -22
  165. package/src/utils.ts +0 -47
  166. package/src/core/lib/validateImageBitmap.ts +0 -87
@@ -17,19 +17,14 @@
17
17
  * limitations under the License.
18
18
  */
19
19
 
20
- import type { CreateImageBitmapSupport } from '../lib/validateImageBitmap.js';
21
- import { type TextureData } from '../textures/Texture.js';
20
+ import type { ImageResponse } from '../../../textures/ImageTexture.js';
22
21
 
23
22
  type MessageCallback = [(value: any) => void, (reason: any) => void];
24
- interface getImageReturn {
25
- data: ImageBitmap;
26
- premultiplyAlpha: boolean | null;
27
- }
28
23
 
29
24
  interface ImageWorkerMessage {
30
25
  id: number;
31
26
  src: string;
32
- data: getImageReturn;
27
+ data: ImageResponse;
33
28
  error: string;
34
29
  sx: number | null;
35
30
  sy: number | null;
@@ -59,15 +54,8 @@ function createImageWorker() {
59
54
  y: number | null,
60
55
  width: number | null,
61
56
  height: number | null,
62
- options: {
63
- supportsOptionsCreateImageBitmap: boolean;
64
- supportsFullCreateImageBitmap: boolean;
65
- },
66
- ): Promise<getImageReturn> {
57
+ ): Promise<ImageResponse> {
67
58
  return new Promise(function (resolve, reject) {
68
- var supportsOptionsCreateImageBitmap =
69
- options.supportsOptionsCreateImageBitmap;
70
- var supportsFullCreateImageBitmap = options.supportsFullCreateImageBitmap;
71
59
  var xhr = new XMLHttpRequest();
72
60
  xhr.open('GET', src, true);
73
61
  xhr.responseType = 'blob';
@@ -91,11 +79,7 @@ function createImageWorker() {
91
79
  : hasAlphaChannel(blob.type);
92
80
 
93
81
  // createImageBitmap with crop and options
94
- if (
95
- supportsFullCreateImageBitmap === true &&
96
- width !== null &&
97
- height !== null
98
- ) {
82
+ if (width !== null && height !== null) {
99
83
  createImageBitmap(blob, x || 0, y || 0, width, height, {
100
84
  premultiplyAlpha: withAlphaChannel ? 'premultiply' : 'none',
101
85
  colorSpaceConversion: 'none',
@@ -108,19 +92,6 @@ function createImageWorker() {
108
92
  reject(error);
109
93
  });
110
94
  return;
111
- } else if (
112
- supportsOptionsCreateImageBitmap === false &&
113
- supportsOptionsCreateImageBitmap === false
114
- ) {
115
- // Fallback for browsers that do not support createImageBitmap with options
116
- // this is supported for Chrome v50 to v52/54 that doesn't support options
117
- createImageBitmap(blob)
118
- .then(function (data) {
119
- resolve({ data, premultiplyAlpha: premultiplyAlpha });
120
- })
121
- .catch(function (error) {
122
- reject(error);
123
- });
124
95
  } else {
125
96
  createImageBitmap(blob, {
126
97
  premultiplyAlpha: withAlphaChannel ? 'premultiply' : 'none',
@@ -155,14 +126,7 @@ function createImageWorker() {
155
126
  var width = event.data.sw;
156
127
  var height = event.data.sh;
157
128
 
158
- // these will be set to true if the browser supports the createImageBitmap options or full
159
- var supportsOptionsCreateImageBitmap = false;
160
- var supportsFullCreateImageBitmap = false;
161
-
162
- getImage(src, premultiplyAlpha, x, y, width, height, {
163
- supportsOptionsCreateImageBitmap,
164
- supportsFullCreateImageBitmap,
165
- })
129
+ getImage(src, premultiplyAlpha, x, y, width, height)
166
130
  .then(function (data) {
167
131
  // @ts-ignore ts has wrong postMessage signature
168
132
  self.postMessage({ id: id, src: src, data: data }, [data.data]);
@@ -181,14 +145,8 @@ export class ImageWorkerManager {
181
145
  workerLoad: number[] = [];
182
146
  nextId = 0;
183
147
 
184
- constructor(
185
- numImageWorkers: number,
186
- createImageBitmapSupport: CreateImageBitmapSupport,
187
- ) {
188
- this.workers = this.createWorkers(
189
- numImageWorkers,
190
- createImageBitmapSupport,
191
- );
148
+ constructor(numImageWorkers: number) {
149
+ this.workers = this.createWorkers(numImageWorkers);
192
150
  this.workers.forEach((worker, index) => {
193
151
  worker.onmessage = (event) => this.handleMessage(event, index);
194
152
  });
@@ -213,36 +171,14 @@ export class ImageWorkerManager {
213
171
  }
214
172
  }
215
173
 
216
- private createWorkers(
217
- numWorkers = 1,
218
- createImageBitmapSupport: CreateImageBitmapSupport,
219
- ): Worker[] {
174
+ private createWorkers(numWorkers = 1): Worker[] {
220
175
  let workerCode = `(${createImageWorker.toString()})()`;
221
176
 
222
- // Replace placeholders with actual initialization values
223
- if (createImageBitmapSupport.options === true) {
224
- workerCode = workerCode.replace(
225
- 'var supportsOptionsCreateImageBitmap = false;',
226
- 'var supportsOptionsCreateImageBitmap = true;',
227
- );
228
- }
229
-
230
- if (createImageBitmapSupport.full === true) {
231
- workerCode = workerCode.replace(
232
- 'var supportsOptionsCreateImageBitmap = false;',
233
- 'var supportsOptionsCreateImageBitmap = true;',
234
- );
235
-
236
- workerCode = workerCode.replace(
237
- 'var supportsFullCreateImageBitmap = false;',
238
- 'var supportsFullCreateImageBitmap = true;',
239
- );
240
- }
241
-
242
177
  workerCode = workerCode.replace('"use strict";', '');
243
178
  const blob: Blob = new Blob([workerCode], {
244
179
  type: 'application/javascript',
245
180
  });
181
+
246
182
  const blobURL: string = (self.URL ? URL : webkitURL).createObjectURL(blob);
247
183
  const workers: Worker[] = [];
248
184
  for (let i = 0; i < numWorkers; i++) {
@@ -280,7 +216,7 @@ export class ImageWorkerManager {
280
216
  sy: number | null,
281
217
  sw: number | null,
282
218
  sh: number | null,
283
- ): Promise<TextureData> {
219
+ ): Promise<ImageResponse> {
284
220
  return new Promise((resolve, reject) => {
285
221
  try {
286
222
  if (this.workers) {
@@ -0,0 +1,40 @@
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
+ export const createImageBitmap = (
21
+ blob: ImageBitmapSource,
22
+ sxOrOptions?: number | ImageBitmapOptions,
23
+ sy?: number,
24
+ sw?: number,
25
+ sh?: number,
26
+ options?: ImageBitmapOptions,
27
+ ): Promise<ImageBitmap> => {
28
+ if (typeof sxOrOptions === 'number') {
29
+ return createImageBitmap(
30
+ blob,
31
+ sxOrOptions,
32
+ sy ?? 0,
33
+ sw ?? 0,
34
+ sh ?? 0,
35
+ options,
36
+ );
37
+ } else {
38
+ return createImageBitmap(blob, sxOrOptions);
39
+ }
40
+ };
@@ -16,8 +16,9 @@
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
18
  */
19
- import { type CompressedData, type TextureData } from '../textures/Texture.js';
20
- import type { WebGlContextWrapper } from './WebGlContextWrapper.js';
19
+ import { type CompressedData } from '../../../textures/Texture.js';
20
+ import type { ImageResponse } from '../../../textures/ImageTexture.js';
21
+ import type { WebGlContextWrapper } from '../WebGlContextWrapper.js';
21
22
 
22
23
  export type UploadCompressedTextureFunction = (
23
24
  glw: WebGlContextWrapper,
@@ -25,18 +26,6 @@ export type UploadCompressedTextureFunction = (
25
26
  data: CompressedData,
26
27
  ) => void;
27
28
 
28
- /**
29
- * Tests if the given location is a compressed texture container
30
- * @param url
31
- * @remarks
32
- * This function is used to determine if the given image url is a compressed
33
- * and only supports the following extensions: .ktx and .pvr
34
- * @returns
35
- */
36
- export function isCompressedTextureContainer(src: string): boolean {
37
- return /\.(ktx|pvr)$/.test(src);
38
- }
39
-
40
29
  const PVR_MAGIC = 0x03525650; // 'PVR3' in little-endian
41
30
  const PVR_TO_GL_INTERNAL_FORMAT: Record<string, number> = {
42
31
  0: 0x8c01,
@@ -72,7 +61,7 @@ const KTX_IDENTIFIER = [
72
61
  */
73
62
  export const loadCompressedTexture = async (
74
63
  url: string,
75
- ): Promise<TextureData> => {
64
+ ): Promise<ImageResponse> => {
76
65
  try {
77
66
  const response = await fetch(url);
78
67
  if (!response.ok) {
@@ -133,7 +122,7 @@ function readUint24(view: DataView, offset: number) {
133
122
  * @param view
134
123
  * @returns
135
124
  */
136
- const loadASTC = async function (view: DataView): Promise<TextureData> {
125
+ const loadASTC = async function (view: DataView): Promise<ImageResponse> {
137
126
  const blockX = view.getUint8(4);
138
127
  const blockY = view.getUint8(5);
139
128
  const sizeX = readUint24(view, 7);
@@ -167,43 +156,18 @@ const loadASTC = async function (view: DataView): Promise<TextureData> {
167
156
  mipmaps,
168
157
  w: sizeX,
169
158
  h: sizeY,
170
- type: 'astc',
159
+ type: 'ASTC',
171
160
  },
172
161
  premultiplyAlpha: false,
173
162
  };
174
163
  };
175
164
 
176
- const uploadASTC = function (
177
- glw: WebGlContextWrapper,
178
- texture: WebGLTexture,
179
- data: CompressedData,
180
- ) {
181
- if (glw.getExtension('WEBGL_compressed_texture_astc') === null) {
182
- throw new Error('ASTC compressed textures not supported by this device');
183
- }
184
-
185
- glw.bindTexture(texture);
186
-
187
- const { glInternalFormat, mipmaps, w, h } = data;
188
- if (mipmaps === undefined) {
189
- return;
190
- }
191
-
192
- const view = new Uint8Array(mipmaps[0]!);
193
-
194
- glw.compressedTexImage2D(0, glInternalFormat, w, h, 0, view);
195
- // ASTC textures MUST use no mipmaps unless stored
196
- glw.texParameteri(glw.TEXTURE_WRAP_S, glw.CLAMP_TO_EDGE);
197
- glw.texParameteri(glw.TEXTURE_WRAP_T, glw.CLAMP_TO_EDGE);
198
- glw.texParameteri(glw.TEXTURE_MAG_FILTER, glw.LINEAR);
199
- glw.texParameteri(glw.TEXTURE_MIN_FILTER, glw.LINEAR);
200
- };
201
165
  /**
202
166
  * Loads a KTX texture container and returns the texture data
203
167
  * @param view
204
168
  * @returns
205
169
  */
206
- const loadKTX = async function (view: DataView): Promise<TextureData> {
170
+ const loadKTX = async function (view: DataView): Promise<ImageResponse> {
207
171
  const endianness = view.getUint32(12, true);
208
172
  const littleEndian = endianness === 0x04030201;
209
173
  if (littleEndian === false && endianness !== 0x01020304) {
@@ -267,58 +231,12 @@ const loadKTX = async function (view: DataView): Promise<TextureData> {
267
231
  mipmaps,
268
232
  w: width,
269
233
  h: height,
270
- type: 'ktx',
234
+ type: 'KTX',
271
235
  },
272
236
  premultiplyAlpha: false,
273
237
  };
274
238
  };
275
239
 
276
- const uploadKTX = function (
277
- glw: WebGlContextWrapper,
278
- texture: WebGLTexture,
279
- data: CompressedData,
280
- ) {
281
- const { glInternalFormat, mipmaps, w: width, h: height, blockInfo } = data;
282
- if (mipmaps === undefined) {
283
- return;
284
- }
285
- glw.bindTexture(texture);
286
-
287
- const blockWidth = blockInfo.width;
288
- const blockHeight = blockInfo.height;
289
- let w = width;
290
- let h = height;
291
-
292
- for (let i = 0; i < mipmaps!.length; i++) {
293
- let view = new Uint8Array(mipmaps![i]!);
294
-
295
- const uploadW = Math.ceil(w / blockWidth) * blockWidth;
296
- const uploadH = Math.ceil(h / blockHeight) * blockHeight;
297
-
298
- const expectedBytes =
299
- Math.ceil(w / blockWidth) * Math.ceil(h / blockHeight) * blockInfo.bytes;
300
-
301
- if (view.byteLength < expectedBytes) {
302
- const padded = new Uint8Array(expectedBytes);
303
- padded.set(view);
304
- view = padded;
305
- }
306
-
307
- glw.compressedTexImage2D(i, glInternalFormat, uploadW, uploadH, 0, view);
308
-
309
- w = Math.max(1, w >> 1);
310
- h = Math.max(1, h >> 1);
311
- }
312
-
313
- glw.texParameteri(glw.TEXTURE_WRAP_S, glw.CLAMP_TO_EDGE);
314
- glw.texParameteri(glw.TEXTURE_WRAP_T, glw.CLAMP_TO_EDGE);
315
- glw.texParameteri(glw.TEXTURE_MAG_FILTER, glw.LINEAR);
316
- glw.texParameteri(
317
- glw.TEXTURE_MIN_FILTER,
318
- mipmaps!.length > 1 ? glw.LINEAR_MIPMAP_LINEAR : glw.LINEAR,
319
- );
320
- };
321
-
322
240
  function pvrtcMipSize(width: number, height: number, bpp: 2 | 4) {
323
241
  const minW = bpp === 2 ? 16 : 8;
324
242
  const minH = 8;
@@ -327,7 +245,7 @@ function pvrtcMipSize(width: number, height: number, bpp: 2 | 4) {
327
245
  return (w * h * bpp) / 8;
328
246
  }
329
247
 
330
- const loadPVR = async function (view: DataView): Promise<TextureData> {
248
+ const loadPVR = async function (view: DataView): Promise<ImageResponse> {
331
249
  const pixelFormatLow = view.getUint32(8, true);
332
250
  const internalFormat = PVR_TO_GL_INTERNAL_FORMAT[pixelFormatLow];
333
251
 
@@ -405,50 +323,22 @@ const loadPVR = async function (view: DataView): Promise<TextureData> {
405
323
  mipmaps,
406
324
  w: width,
407
325
  h: height,
408
- type: 'pvr',
326
+ type: 'PVR',
409
327
  },
410
328
  premultiplyAlpha: false,
411
329
  };
412
330
  };
413
331
 
414
- const uploadPVR = function (
415
- glw: WebGlContextWrapper,
416
- texture: WebGLTexture,
417
- data: CompressedData,
418
- ) {
419
- const { glInternalFormat, mipmaps, w: width, h: height } = data;
420
- if (mipmaps === undefined) {
421
- return;
422
- }
423
- glw.bindTexture(texture);
424
-
425
- let w = width;
426
- let h = height;
427
-
428
- for (let i = 0; i < mipmaps!.length; i++) {
429
- glw.compressedTexImage2D(
430
- i,
431
- glInternalFormat,
432
- w,
433
- h,
434
- 0,
435
- new Uint8Array(mipmaps[i]!),
436
- );
437
-
438
- w = Math.max(1, w >> 1);
439
- h = Math.max(1, h >> 1);
440
- }
441
-
442
- glw.texParameteri(glw.TEXTURE_WRAP_S, glw.CLAMP_TO_EDGE);
443
- glw.texParameteri(glw.TEXTURE_WRAP_T, glw.CLAMP_TO_EDGE);
444
- glw.texParameteri(glw.TEXTURE_MAG_FILTER, glw.LINEAR);
445
- glw.texParameteri(
446
- glw.TEXTURE_MIN_FILTER,
447
- mipmaps.length > 1 ? glw.LINEAR_MIPMAP_LINEAR : glw.LINEAR,
448
- );
449
- };
332
+ export interface CompressedImageData {
333
+ blockInfo: BlockInfo;
334
+ glInternalFormat: number;
335
+ mipmaps: ArrayBuffer[];
336
+ w: number;
337
+ h: number;
338
+ type: 'PVR' | 'KTX' | 'ASTC';
339
+ }
450
340
 
451
- type BlockInfo = {
341
+ export type BlockInfo = {
452
342
  width: number;
453
343
  height: number;
454
344
  bytes: number;
@@ -499,12 +389,3 @@ export const blockInfoMap: { [key: number]: BlockInfo } = {
499
389
  0x93b5: BLOCK_12x12x16, // 12x12
500
390
  0x93d5: BLOCK_12x12x16,
501
391
  };
502
-
503
- export const uploadCompressedTexture: Record<
504
- string,
505
- UploadCompressedTextureFunction
506
- > = {
507
- ktx: uploadKTX,
508
- pvr: uploadPVR,
509
- astc: uploadASTC,
510
- };
@@ -17,20 +17,8 @@
17
17
  * limitations under the License.
18
18
  */
19
19
 
20
- import { assertTruthy } from '../../utils.js';
21
- import { type TextureData } from '../textures/Texture.js';
22
-
23
- /**
24
- * Tests if the given location is a SVG
25
- * @param url
26
- * @remarks
27
- * This function is used to determine if the given image url is a SVG
28
- * image
29
- * @returns
30
- */
31
- export function isSvgImage(url: string): boolean {
32
- return /\.(svg)(\?.*)?$/.test(url);
33
- }
20
+ import { assertTruthy } from '../../../../utils.js';
21
+ import type { ImageResponse } from '../../../textures/ImageTexture.js';
34
22
 
35
23
  /**
36
24
  * Loads a SVG image
@@ -45,7 +33,7 @@ export const loadSvg = (
45
33
  sy: number | null,
46
34
  sw: number | null,
47
35
  sh: number | null,
48
- ): Promise<TextureData> => {
36
+ ): Promise<ImageResponse> => {
49
37
  return new Promise((resolve, reject) => {
50
38
  const canvas = document.createElement('canvas');
51
39
  const ctx = canvas.getContext('2d');
@@ -0,0 +1,105 @@
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
+ export const PROTOCOL_REGEX = /^(data|ftps?|https?):/;
21
+
22
+ export function isBase64Image(src: string) {
23
+ return src.startsWith('data:') === true;
24
+ }
25
+
26
+ export function dataURIToBlob(dataURI: string): Blob {
27
+ dataURI = dataURI.replace(/^data:/, '');
28
+
29
+ const type = dataURI.match(/image\/[^;]+/)?.[0] || '';
30
+ const base64 = dataURI.replace(/^[^,]+,/, '');
31
+
32
+ const sliceSize = 1024;
33
+ const byteCharacters = atob(base64);
34
+ const bytesLength = byteCharacters.length;
35
+ const slicesCount = Math.ceil(bytesLength / sliceSize);
36
+ const byteArrays = new Array(slicesCount);
37
+
38
+ for (let sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
39
+ const begin = sliceIndex * sliceSize;
40
+ const end = Math.min(begin + sliceSize, bytesLength);
41
+
42
+ const bytes = new Array(end - begin);
43
+ for (let offset = begin, i = 0; offset < end; ++i, ++offset) {
44
+ bytes[i] = byteCharacters[offset]?.charCodeAt(0);
45
+ }
46
+ byteArrays[sliceIndex] = new Uint8Array(bytes);
47
+ }
48
+ return new Blob(byteArrays, { type });
49
+ }
50
+
51
+ export function convertUrlToAbsolute(url: string): string {
52
+ // handle local file imports if the url isn't remote resource or data blob
53
+ if (self.location.protocol === 'file:' && !PROTOCOL_REGEX.test(url)) {
54
+ const path = self.location.pathname.split('/');
55
+ path.pop();
56
+ const basePath = path.join('/');
57
+ const baseUrl = self.location.protocol + '//' + basePath;
58
+
59
+ // check if url has a leading dot
60
+ if (url.charAt(0) === '.') {
61
+ url = url.slice(1);
62
+ }
63
+
64
+ // check if url has a leading slash
65
+ if (url.charAt(0) === '/') {
66
+ url = url.slice(1);
67
+ }
68
+
69
+ return baseUrl + '/' + url;
70
+ }
71
+
72
+ const absoluteUrl = new URL(url, self.location.href);
73
+ return absoluteUrl.href;
74
+ }
75
+
76
+ export function createWebGLContext(
77
+ canvas: HTMLCanvasElement | OffscreenCanvas,
78
+ forceWebGL2 = false,
79
+ ): WebGLRenderingContext {
80
+ const config: WebGLContextAttributes = {
81
+ alpha: true,
82
+ antialias: false,
83
+ depth: false,
84
+ stencil: true,
85
+ desynchronized: false,
86
+ // Disabled because it prevents Visual Regression Tests from working
87
+ // failIfMajorPerformanceCaveat: true,
88
+ powerPreference: 'high-performance',
89
+ premultipliedAlpha: true,
90
+ preserveDrawingBuffer: false,
91
+ };
92
+ const gl =
93
+ // TODO: Remove this assertion once this issue is fixed in TypeScript
94
+ // https://github.com/microsoft/TypeScript/issues/53614
95
+ (canvas.getContext(forceWebGL2 ? 'webgl2' : 'webgl', config) ||
96
+ canvas.getContext(
97
+ 'experimental-webgl' as 'webgl',
98
+ config,
99
+ )) as unknown as WebGLRenderingContext | null;
100
+ if (!gl) {
101
+ throw new Error('Unable to create WebGL context');
102
+ }
103
+
104
+ return gl;
105
+ }
@@ -25,20 +25,12 @@ import type { Texture, TextureCoords } from '../textures/Texture.js';
25
25
  import { CoreContextTexture } from './CoreContextTexture.js';
26
26
  import type { CoreShaderType, CoreShaderNode } from './CoreShaderNode.js';
27
27
 
28
- export interface CoreRendererOptions {
29
- stage: Stage;
30
- canvas: HTMLCanvasElement | OffscreenCanvas;
31
- contextSpy: ContextSpy | null;
32
- forceWebGL2: boolean;
33
- }
34
-
35
28
  export interface BufferInfo {
36
29
  totalUsed: number;
37
30
  totalAvailable: number;
38
31
  }
39
32
 
40
33
  export abstract class CoreRenderer {
41
- public options: CoreRendererOptions;
42
34
  public mode: 'webgl' | 'canvas' | undefined;
43
35
  defaultTextureCoords: TextureCoords | undefined = undefined;
44
36
  readonly stage: Stage;
@@ -46,9 +38,8 @@ export abstract class CoreRenderer {
46
38
  //// Core Managers
47
39
  rttNodes: CoreNode[] = [];
48
40
 
49
- constructor(options: CoreRendererOptions) {
50
- this.options = options;
51
- this.stage = options.stage;
41
+ constructor(stage: Stage) {
42
+ this.stage = stage;
52
43
  }
53
44
 
54
45
  abstract reset(): void;
@@ -20,11 +20,12 @@ import type { CoreNode } from '../../CoreNode.js';
20
20
  import { SubTexture } from '../../textures/SubTexture.js';
21
21
  import { TextureType, type Texture } from '../../textures/Texture.js';
22
22
  import type { CoreContextTexture } from '../CoreContextTexture.js';
23
- import { CoreRenderer, type CoreRendererOptions } from '../CoreRenderer.js';
23
+ import { CoreRenderer } from '../CoreRenderer.js';
24
24
  import { CanvasTexture } from './CanvasTexture.js';
25
25
  import { parseColor } from '../../lib/colorParser.js';
26
26
  import { CanvasShaderNode, type CanvasShaderType } from './CanvasShaderNode.js';
27
27
  import { normalizeCanvasColor } from '../../lib/colorCache.js';
28
+ import type { Stage } from '../../Stage.js';
28
29
 
29
30
  export class CanvasRenderer extends CoreRenderer {
30
31
  private context: CanvasRenderingContext2D;
@@ -34,11 +35,12 @@ export class CanvasRenderer extends CoreRenderer {
34
35
  public renderToTextureActive = false;
35
36
  activeRttNode: CoreNode | null = null;
36
37
 
37
- constructor(options: CoreRendererOptions) {
38
- super(options);
38
+ constructor(stage: Stage) {
39
+ super(stage);
39
40
 
40
41
  this.mode = 'canvas';
41
- const { canvas } = options;
42
+ const platform = stage.platform!;
43
+ const canvas = platform.canvas!;
42
44
  this.canvas = canvas as HTMLCanvasElement;
43
45
  this.context = canvas.getContext('2d') as CanvasRenderingContext2D;
44
46
  this.pixelRatio = this.stage.pixelRatio;
@@ -70,7 +70,8 @@ export class SdfRenderOp extends CoreRenderOp {
70
70
  }
71
71
 
72
72
  draw() {
73
- const { glw, options, stage } = this.renderer;
73
+ const { glw, stage } = this.renderer;
74
+ const canvas = stage.platform!.canvas!;
74
75
 
75
76
  stage.shManager.useShader(this.shader.program);
76
77
  this.shader.program.bindRenderOp(this);
@@ -82,7 +83,7 @@ export class SdfRenderOp extends CoreRenderOp {
82
83
  const clipWidth = Math.round(this.clippingRect.w * pixelRatio);
83
84
  const clipHeight = Math.round(this.clippingRect.h * pixelRatio);
84
85
  let clipY = Math.round(
85
- options.canvas.height - clipHeight - this.clippingRect.y * pixelRatio,
86
+ canvas.height - clipHeight - this.clippingRect.y * pixelRatio,
86
87
  );
87
88
  // if parent has render texture, we need to adjust the scissor rect
88
89
  // to be relative to the parent's framebuffer
@@ -19,7 +19,7 @@
19
19
 
20
20
  import type { Dimensions } from '../../../common/CommonTypes.js';
21
21
  import type { TextureMemoryManager } from '../../TextureMemoryManager.js';
22
- import type { WebGlContextWrapper } from '../../lib/WebGlContextWrapper.js';
22
+ import type { GlContextWrapper } from '../../platforms/GlContextWrapper.js';
23
23
  import type { Bound } from '../../lib/utils.js';
24
24
  import type { RenderTexture } from '../../textures/RenderTexture.js';
25
25
  import { WebGlCtxTexture } from './WebGlCtxTexture.js';
@@ -37,7 +37,7 @@ export class WebGlCtxRenderTexture extends WebGlCtxTexture {
37
37
  };
38
38
 
39
39
  constructor(
40
- glw: WebGlContextWrapper,
40
+ glw: GlContextWrapper,
41
41
  memManager: TextureMemoryManager,
42
42
  textureSource: RenderTexture,
43
43
  ) {
@@ -20,7 +20,7 @@
20
20
  import type { Dimensions } from '../../../common/CommonTypes.js';
21
21
  import { assertTruthy } from '../../../utils.js';
22
22
  import type { TextureMemoryManager } from '../../TextureMemoryManager.js';
23
- import type { WebGlContextWrapper } from '../../lib/WebGlContextWrapper.js';
23
+ import type { GlContextWrapper } from '../../platforms/GlContextWrapper.js';
24
24
  import type { SubTexture } from '../../textures/SubTexture.js';
25
25
  import type { SubTextureProps } from '../../textures/SubTexture.js';
26
26
  import type { CompressedData } from '../../textures/Texture.js';
@@ -28,7 +28,7 @@ import { WebGlCtxTexture } from './WebGlCtxTexture.js';
28
28
 
29
29
  export class WebGlCtxSubTexture extends WebGlCtxTexture {
30
30
  constructor(
31
- glw: WebGlContextWrapper,
31
+ glw: GlContextWrapper,
32
32
  memManager: TextureMemoryManager,
33
33
  textureSource: SubTexture,
34
34
  ) {