@lightningjs/renderer 3.0.0-beta21 → 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 (165) hide show
  1. package/README.md +93 -0
  2. package/dist/exports/index.d.ts +1 -0
  3. package/dist/exports/index.js +1 -0
  4. package/dist/exports/index.js.map +1 -1
  5. package/dist/exports/platform.d.ts +7 -0
  6. package/dist/exports/platform.js +27 -0
  7. package/dist/exports/platform.js.map +1 -0
  8. package/dist/src/common/CommonTypes.d.ts +2 -1
  9. package/dist/src/core/AutosizeManager.d.ts +29 -0
  10. package/dist/src/core/AutosizeManager.js +169 -0
  11. package/dist/src/core/AutosizeManager.js.map +1 -0
  12. package/dist/src/core/CoreNode.js +10 -14
  13. package/dist/src/core/CoreNode.js.map +1 -1
  14. package/dist/src/core/CoreTextureManager.d.ts +0 -13
  15. package/dist/src/core/CoreTextureManager.js +4 -78
  16. package/dist/src/core/CoreTextureManager.js.map +1 -1
  17. package/dist/src/core/Stage.js +2 -12
  18. package/dist/src/core/Stage.js.map +1 -1
  19. package/dist/src/core/animations/CoreAnimationController.d.ts +1 -1
  20. package/dist/src/core/animations/CoreAnimationController.js +4 -2
  21. package/dist/src/core/animations/CoreAnimationController.js.map +1 -1
  22. package/dist/src/core/lib/collectionUtils.js +3 -2
  23. package/dist/src/core/lib/collectionUtils.js.map +1 -1
  24. package/dist/src/core/lib/utils.d.ts +0 -5
  25. package/dist/src/core/lib/utils.js +0 -63
  26. package/dist/src/core/lib/utils.js.map +1 -1
  27. package/dist/src/core/platforms/GlContextWrapper.d.ts +136 -0
  28. package/dist/src/core/platforms/GlContextWrapper.js +32 -0
  29. package/dist/src/core/platforms/GlContextWrapper.js.map +1 -0
  30. package/dist/src/core/platforms/Platform.d.ts +74 -13
  31. package/dist/src/core/platforms/Platform.js +18 -0
  32. package/dist/src/core/platforms/Platform.js.map +1 -1
  33. package/dist/src/core/platforms/web/WebGlContextWrapper.d.ts +776 -0
  34. package/dist/src/core/platforms/web/WebGlContextWrapper.js +1208 -0
  35. package/dist/src/core/platforms/web/WebGlContextWrapper.js.map +1 -0
  36. package/dist/src/core/platforms/web/WebPlatform.d.ts +13 -2
  37. package/dist/src/core/platforms/web/WebPlatform.js +109 -8
  38. package/dist/src/core/platforms/web/WebPlatform.js.map +1 -1
  39. package/dist/src/core/platforms/web/WebPlatformChrome50.d.ts +17 -0
  40. package/dist/src/core/platforms/web/WebPlatformChrome50.js +50 -0
  41. package/dist/src/core/platforms/web/WebPlatformChrome50.js.map +1 -0
  42. package/dist/src/core/platforms/web/WebPlatformLegacy.d.ts +18 -0
  43. package/dist/src/core/platforms/web/WebPlatformLegacy.js +99 -0
  44. package/dist/src/core/platforms/web/WebPlatformLegacy.js.map +1 -0
  45. package/dist/src/core/platforms/web/WebPlatformNext.d.ts +21 -0
  46. package/dist/src/core/platforms/web/WebPlatformNext.js +52 -0
  47. package/dist/src/core/platforms/web/WebPlatformNext.js.map +1 -0
  48. package/dist/src/core/platforms/web/lib/ImageWorker.d.ts +15 -0
  49. package/dist/src/core/platforms/web/lib/ImageWorker.js +189 -0
  50. package/dist/src/core/platforms/web/lib/ImageWorker.js.map +1 -0
  51. package/dist/src/core/platforms/web/lib/createImageBitmap.d.ts +1 -0
  52. package/dist/src/core/platforms/web/lib/createImageBitmap.js +27 -0
  53. package/dist/src/core/platforms/web/lib/createImageBitmap.js.map +1 -0
  54. package/dist/src/core/platforms/web/lib/textureCompression.d.ts +26 -0
  55. package/dist/src/core/platforms/web/lib/textureCompression.js +301 -0
  56. package/dist/src/core/platforms/web/lib/textureCompression.js.map +1 -0
  57. package/dist/src/core/platforms/web/lib/textureSvg.d.ts +7 -0
  58. package/dist/src/core/platforms/web/lib/textureSvg.js +51 -0
  59. package/dist/src/core/platforms/web/lib/textureSvg.js.map +1 -0
  60. package/dist/src/core/platforms/web/lib/utils.d.ts +5 -0
  61. package/dist/src/core/platforms/web/lib/utils.js +86 -0
  62. package/dist/src/core/platforms/web/lib/utils.js.map +1 -0
  63. package/dist/src/core/renderers/CoreRenderer.d.ts +1 -9
  64. package/dist/src/core/renderers/CoreRenderer.js +2 -4
  65. package/dist/src/core/renderers/CoreRenderer.js.map +1 -1
  66. package/dist/src/core/renderers/canvas/CanvasRenderer.d.ts +3 -2
  67. package/dist/src/core/renderers/canvas/CanvasRenderer.js +4 -3
  68. package/dist/src/core/renderers/canvas/CanvasRenderer.js.map +1 -1
  69. package/dist/src/core/renderers/webgl/SdfRenderOp.js +3 -2
  70. package/dist/src/core/renderers/webgl/SdfRenderOp.js.map +1 -1
  71. package/dist/src/core/renderers/webgl/WebGlCtxRenderTexture.d.ts +2 -2
  72. package/dist/src/core/renderers/webgl/WebGlCtxRenderTexture.js.map +1 -1
  73. package/dist/src/core/renderers/webgl/WebGlCtxSubTexture.d.ts +2 -2
  74. package/dist/src/core/renderers/webgl/WebGlCtxSubTexture.js.map +1 -1
  75. package/dist/src/core/renderers/webgl/WebGlCtxTexture.d.ts +3 -3
  76. package/dist/src/core/renderers/webgl/WebGlCtxTexture.js +1 -2
  77. package/dist/src/core/renderers/webgl/WebGlCtxTexture.js.map +1 -1
  78. package/dist/src/core/renderers/webgl/WebGlRenderOp.d.ts +3 -2
  79. package/dist/src/core/renderers/webgl/WebGlRenderOp.js +3 -1
  80. package/dist/src/core/renderers/webgl/WebGlRenderOp.js.map +1 -1
  81. package/dist/src/core/renderers/webgl/WebGlRenderer.d.ts +5 -5
  82. package/dist/src/core/renderers/webgl/WebGlRenderer.js +7 -8
  83. package/dist/src/core/renderers/webgl/WebGlRenderer.js.map +1 -1
  84. package/dist/src/core/renderers/webgl/WebGlShaderNode.d.ts +2 -2
  85. package/dist/src/core/renderers/webgl/WebGlShaderProgram.d.ts +2 -2
  86. package/dist/src/core/renderers/webgl/WebGlShaderProgram.js.map +1 -1
  87. package/dist/src/core/renderers/webgl/internal/RendererUtils.d.ts +4 -4
  88. package/dist/src/core/renderers/webgl/internal/RendererUtils.js.map +1 -1
  89. package/dist/src/core/renderers/webgl/internal/ShaderUtils.d.ts +3 -3
  90. package/dist/src/core/renderers/webgl/internal/ShaderUtils.js.map +1 -1
  91. package/dist/src/core/shaders/webgl/Border.js +13 -17
  92. package/dist/src/core/shaders/webgl/Border.js.map +1 -1
  93. package/dist/src/core/shaders/webgl/RoundedWithBorder.js +12 -21
  94. package/dist/src/core/shaders/webgl/RoundedWithBorder.js.map +1 -1
  95. package/dist/src/core/shaders/webgl/RoundedWithBorderAndShadow.js +10 -12
  96. package/dist/src/core/shaders/webgl/RoundedWithBorderAndShadow.js.map +1 -1
  97. package/dist/src/core/text-rendering/CanvasFont.d.ts +14 -0
  98. package/dist/src/core/text-rendering/CanvasFont.js +111 -0
  99. package/dist/src/core/text-rendering/CanvasFont.js.map +1 -0
  100. package/dist/src/core/text-rendering/CoreFont.d.ts +33 -0
  101. package/dist/src/core/text-rendering/CoreFont.js +48 -0
  102. package/dist/src/core/text-rendering/CoreFont.js.map +1 -0
  103. package/dist/src/core/text-rendering/FontManager.d.ts +11 -0
  104. package/dist/src/core/text-rendering/FontManager.js +42 -0
  105. package/dist/src/core/text-rendering/FontManager.js.map +1 -0
  106. package/dist/src/core/text-rendering/SdfFont.d.ts +29 -0
  107. package/dist/src/core/text-rendering/SdfFont.js +142 -0
  108. package/dist/src/core/text-rendering/SdfFont.js.map +1 -0
  109. package/dist/src/core/textures/ImageTexture.d.ts +24 -11
  110. package/dist/src/core/textures/ImageTexture.js +32 -95
  111. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  112. package/dist/src/core/textures/Texture.d.ts +5 -4
  113. package/dist/src/core/textures/Texture.js.map +1 -1
  114. package/dist/src/core/utils.d.ts +1 -1
  115. package/dist/src/main-api/Inspector.d.ts +4 -0
  116. package/dist/src/main-api/Inspector.js +160 -0
  117. package/dist/src/main-api/Inspector.js.map +1 -1
  118. package/dist/src/main-api/Renderer.js +18 -21
  119. package/dist/src/main-api/Renderer.js.map +1 -1
  120. package/dist/src/utils.d.ts +0 -2
  121. package/dist/src/utils.js +0 -36
  122. package/dist/src/utils.js.map +1 -1
  123. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  124. package/exports/index.ts +5 -0
  125. package/exports/platform.ts +31 -0
  126. package/package.json +3 -2
  127. package/src/common/CommonTypes.ts +2 -1
  128. package/src/core/CoreNode.ts +11 -15
  129. package/src/core/CoreTextureManager.ts +10 -103
  130. package/src/core/Stage.ts +1 -14
  131. package/src/core/animations/CoreAnimationController.ts +5 -2
  132. package/src/core/lib/collectionUtils.ts +3 -2
  133. package/src/core/lib/utils.ts +0 -78
  134. package/src/core/platforms/GlContextWrapper.ts +291 -0
  135. package/src/core/platforms/Platform.ts +121 -28
  136. package/src/core/{lib → platforms/web}/WebGlContextWrapper.ts +129 -4
  137. package/src/core/platforms/web/WebPlatform.ts +171 -22
  138. package/src/core/platforms/web/WebPlatformChrome50.ts +57 -0
  139. package/src/core/platforms/web/WebPlatformLegacy.ts +140 -0
  140. package/src/core/platforms/web/WebPlatformNext.ts +57 -0
  141. package/src/core/{lib → platforms/web/lib}/ImageWorker.ts +10 -74
  142. package/src/core/platforms/web/lib/createImageBitmap.ts +40 -0
  143. package/src/core/{lib → platforms/web/lib}/textureCompression.ts +19 -138
  144. package/src/core/{lib → platforms/web/lib}/textureSvg.ts +3 -15
  145. package/src/core/platforms/web/lib/utils.ts +105 -0
  146. package/src/core/renderers/CoreRenderer.ts +2 -11
  147. package/src/core/renderers/canvas/CanvasRenderer.ts +6 -4
  148. package/src/core/renderers/webgl/SdfRenderOp.ts +3 -2
  149. package/src/core/renderers/webgl/WebGlCtxRenderTexture.ts +2 -2
  150. package/src/core/renderers/webgl/WebGlCtxSubTexture.ts +2 -2
  151. package/src/core/renderers/webgl/WebGlCtxTexture.ts +3 -4
  152. package/src/core/renderers/webgl/WebGlRenderer.ts +12 -19
  153. package/src/core/renderers/webgl/WebGlShaderNode.ts +2 -2
  154. package/src/core/renderers/webgl/WebGlShaderProgram.ts +2 -2
  155. package/src/core/renderers/webgl/internal/RendererUtils.ts +4 -8
  156. package/src/core/renderers/webgl/internal/ShaderUtils.ts +3 -3
  157. package/src/core/shaders/webgl/Border.ts +13 -17
  158. package/src/core/shaders/webgl/RoundedWithBorder.ts +12 -21
  159. package/src/core/shaders/webgl/RoundedWithBorderAndShadow.ts +10 -12
  160. package/src/core/textures/ImageTexture.ts +42 -161
  161. package/src/core/textures/Texture.ts +11 -7
  162. package/src/main-api/Inspector.ts +215 -0
  163. package/src/main-api/Renderer.ts +24 -22
  164. package/src/utils.ts +0 -47
  165. package/src/core/lib/validateImageBitmap.ts +0 -87
@@ -23,6 +23,7 @@ import type { Dimensions } from '../../common/CommonTypes.js';
23
23
  import { EventEmitter } from '../../common/EventEmitter.js';
24
24
  import type { CoreContextTexture } from '../renderers/CoreContextTexture.js';
25
25
  import type { Bound } from '../lib/utils.js';
26
+ import type { TextureError } from '../TextureError.js';
26
27
 
27
28
  /**
28
29
  * Event handler for when a Texture is freed
@@ -59,7 +60,7 @@ export interface CompressedData {
59
60
  /**
60
61
  * Supported container types ('pvr' or 'ktx').
61
62
  */
62
- type: 'pvr' | 'ktx' | 'astc';
63
+ type: 'PVR' | 'KTX' | 'ASTC';
63
64
 
64
65
  /**
65
66
  * The width of the compressed texture in pixels. Defaults to 0.
@@ -86,7 +87,10 @@ export interface CompressedData {
86
87
  /**
87
88
  * Event handler for when a Texture fails to load
88
89
  */
89
- export type TextureFailedEventHandler = (target: any, error: Error) => void;
90
+ export type TextureFailedEventHandler = (
91
+ target: any,
92
+ error: TextureError,
93
+ ) => void;
90
94
 
91
95
  /**
92
96
  * TextureData that is used to populate a CoreContextTexture
@@ -151,7 +155,7 @@ export abstract class Texture extends EventEmitter {
151
155
  * `null`.
152
156
  */
153
157
  private _dimensions: Dimensions | null = null;
154
- private _error: Error | null = null;
158
+ private _error: TextureError | null = null;
155
159
 
156
160
  // aggregate state
157
161
  public state: TextureState = 'initial';
@@ -205,7 +209,7 @@ export abstract class Texture extends EventEmitter {
205
209
  return this._dimensions;
206
210
  }
207
211
 
208
- get error(): Error | null {
212
+ get error(): TextureError | null {
209
213
  return this._error;
210
214
  }
211
215
 
@@ -393,13 +397,13 @@ export abstract class Texture extends EventEmitter {
393
397
 
394
398
  public setState(
395
399
  state: TextureState,
396
- errorOrDimensions?: Error | Dimensions,
400
+ errorOrDimensions?: TextureError | Dimensions,
397
401
  ): void {
398
402
  if (this.state === state) {
399
403
  return;
400
404
  }
401
405
 
402
- let payload: Error | Dimensions | null = null;
406
+ let payload: TextureError | Dimensions | null = null;
403
407
  if (state === 'loaded') {
404
408
  if (
405
409
  errorOrDimensions !== undefined &&
@@ -413,7 +417,7 @@ export abstract class Texture extends EventEmitter {
413
417
 
414
418
  payload = this._dimensions;
415
419
  } else if (state === 'failed') {
416
- this._error = errorOrDimensions as Error;
420
+ this._error = errorOrDimensions as TextureError;
417
421
  payload = this._error;
418
422
 
419
423
  // increment the retry count for the texture
@@ -11,6 +11,8 @@ import type {
11
11
  } from '../common/IAnimationController.js';
12
12
  import { isProductionEnvironment } from '../utils.js';
13
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';
14
16
 
15
17
  /**
16
18
  * Inspector Options
@@ -204,6 +206,22 @@ const gradientColorPropertyMap = [
204
206
  'colorBr',
205
207
  ];
206
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
+
207
225
  const knownProperties = new Set<string>([
208
226
  ...Object.keys(stylePropertyMap),
209
227
  ...Object.keys(domPropertyMap),
@@ -223,6 +241,7 @@ export class Inspector {
223
241
  private width = 1920;
224
242
  private scaleX = 1;
225
243
  private scaleY = 1;
244
+ private textureMetrics = new Map<Texture, TextureMetrics>();
226
245
 
227
246
  // Performance monitoring for frequent setter calls
228
247
  private static setterCallCount = new Map<
@@ -788,6 +807,94 @@ export class Inspector {
788
807
  node: CoreNode | CoreTextNode,
789
808
  div: HTMLElement,
790
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
+ };
791
898
  // Define traps for each property in knownProperties
792
899
  knownProperties.forEach((property) => {
793
900
  let originalProp = Object.getOwnPropertyDescriptor(node, property);
@@ -802,6 +909,10 @@ export class Inspector {
802
909
  return;
803
910
  }
804
911
 
912
+ if (property === 'text') {
913
+ setupCoreNodeListeners(node);
914
+ }
915
+
805
916
  Object.defineProperty(node, property, {
806
917
  get() {
807
918
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
@@ -818,6 +929,15 @@ export class Inspector {
818
929
  value,
819
930
  node.props,
820
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
+ }
821
941
  },
822
942
  configurable: true,
823
943
  enumerable: true,
@@ -827,6 +947,21 @@ export class Inspector {
827
947
  const originalDestroy = node.destroy;
828
948
  Object.defineProperty(node, 'destroy', {
829
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
+
830
965
  this.destroyNode(node.id);
831
966
  originalDestroy.call(node);
832
967
  },
@@ -856,6 +991,86 @@ export class Inspector {
856
991
  return node;
857
992
  }
858
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
+
859
1074
  public destroy() {
860
1075
  // Stop animation stats timer
861
1076
  this.stopAnimationStatsTimer();
@@ -19,7 +19,7 @@
19
19
 
20
20
  import type { ExtractProps, TextureMap } from '../core/CoreTextureManager.js';
21
21
  import { EventEmitter } from '../common/EventEmitter.js';
22
- import { isProductionEnvironment } from '../utils.js';
22
+ import { assertTruthy, isProductionEnvironment } from '../utils.js';
23
23
  import { Stage, type StageOptions } from '../core/Stage.js';
24
24
  import { CoreNode, type CoreNodeProps } from '../core/CoreNode.js';
25
25
  import { type CoreTextNodeProps } from '../core/CoreTextNode.js';
@@ -550,7 +550,7 @@ export class RendererMain extends EventEmitter {
550
550
  textureProcessingTimeLimit: settings.textureProcessingTimeLimit || 42,
551
551
  canvas: settings.canvas,
552
552
  createImageBitmapSupport: settings.createImageBitmapSupport || 'full',
553
- platform: settings.platform || null,
553
+ platform: settings.platform || WebPlatform,
554
554
  maxRetryCount: settings.maxRetryCount ?? 5,
555
555
  };
556
556
 
@@ -562,29 +562,28 @@ export class RendererMain extends EventEmitter {
562
562
  inspector,
563
563
  } = settings as RendererMainSettings;
564
564
 
565
- let platform;
566
- if (
567
- settings.platform !== undefined &&
568
- settings.platform !== null &&
569
- settings.platform.prototype instanceof Platform === true
570
- ) {
571
- // @ts-ignore - if Platform is a valid class, it will be used
572
- platform = new settings.platform();
573
- } else {
574
- platform = new WebPlatform();
575
- }
565
+ assertTruthy(
566
+ settings.platform,
567
+ 'A platform implementation must be provided in settings.platform',
568
+ );
576
569
 
577
- const canvas = settings.canvas || platform.createCanvas();
570
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
571
+ const platform = new (settings.platform as any)({
572
+ numImageWorkers: settings.numImageWorkers,
573
+ forceWebGL2: settings.forceWebGL2,
574
+ canvas: settings.canvas,
575
+ });
578
576
 
579
577
  const deviceLogicalWidth = appWidth * deviceLogicalPixelRatio;
580
578
  const deviceLogicalHeight = appHeight * deviceLogicalPixelRatio;
581
579
 
582
- this.canvas = canvas;
583
- canvas.width = deviceLogicalWidth * devicePhysicalPixelRatio;
584
- canvas.height = deviceLogicalHeight * devicePhysicalPixelRatio;
580
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unsafe-member-access
581
+ this.canvas = platform.canvas! as HTMLCanvasElement;
582
+ this.canvas.width = deviceLogicalWidth * devicePhysicalPixelRatio;
583
+ this.canvas.height = deviceLogicalHeight * devicePhysicalPixelRatio;
585
584
 
586
- canvas.style.width = `${deviceLogicalWidth}px`;
587
- canvas.style.height = `${deviceLogicalHeight}px`;
585
+ this.canvas.style.width = `${deviceLogicalWidth}px`;
586
+ this.canvas.style.height = `${deviceLogicalHeight}px`;
588
587
 
589
588
  // Initialize the stage
590
589
  this.stage = new Stage({
@@ -629,8 +628,8 @@ export class RendererMain extends EventEmitter {
629
628
  throw new Error('Could not find target element');
630
629
  }
631
630
 
632
- targetEl.appendChild(canvas);
633
- } else if (settings.canvas !== canvas) {
631
+ targetEl.appendChild(this.canvas);
632
+ } else if (settings.canvas !== this.canvas) {
634
633
  throw new Error(
635
634
  'New canvas element could not be appended to undefined target',
636
635
  );
@@ -638,7 +637,10 @@ export class RendererMain extends EventEmitter {
638
637
 
639
638
  // Initialize inspector (if enabled)
640
639
  if (inspector && isProductionEnvironment === false) {
641
- this.inspector = new inspector(canvas, settings as RendererMainSettings);
640
+ this.inspector = new inspector(
641
+ this.canvas,
642
+ settings as RendererMainSettings,
643
+ );
642
644
  }
643
645
  }
644
646
 
package/src/utils.ts CHANGED
@@ -17,53 +17,6 @@
17
17
  * limitations under the License.
18
18
  */
19
19
 
20
- import type { ContextSpy } from './core/lib/ContextSpy.js';
21
-
22
- export function createWebGLContext(
23
- canvas: HTMLCanvasElement | OffscreenCanvas,
24
- forceWebGL2 = false,
25
- contextSpy: ContextSpy | null,
26
- ): WebGLRenderingContext {
27
- const config: WebGLContextAttributes = {
28
- alpha: true,
29
- antialias: false,
30
- depth: false,
31
- stencil: true,
32
- desynchronized: false,
33
- // Disabled because it prevents Visual Regression Tests from working
34
- // failIfMajorPerformanceCaveat: true,
35
- powerPreference: 'high-performance',
36
- premultipliedAlpha: true,
37
- preserveDrawingBuffer: false,
38
- };
39
- const gl =
40
- // TODO: Remove this assertion once this issue is fixed in TypeScript
41
- // https://github.com/microsoft/TypeScript/issues/53614
42
- (canvas.getContext(forceWebGL2 ? 'webgl2' : 'webgl', config) ||
43
- canvas.getContext(
44
- 'experimental-webgl' as 'webgl',
45
- config,
46
- )) as unknown as WebGLRenderingContext | null;
47
- if (!gl) {
48
- throw new Error('Unable to create WebGL context');
49
- }
50
- if (contextSpy) {
51
- // Proxy the GL context to log all GL calls
52
- return new Proxy(gl, {
53
- get(target, prop) {
54
- const value = target[prop as never] as unknown;
55
- if (typeof value === 'function') {
56
- contextSpy.increment(String(prop));
57
- return value.bind(target);
58
- }
59
- return value;
60
- },
61
- });
62
- }
63
-
64
- return gl;
65
- }
66
-
67
20
  /**
68
21
  * Checks if we're in a development environment or not.
69
22
  *
@@ -1,87 +0,0 @@
1
- import type { Platform } from '../platforms/Platform.js';
2
-
3
- export interface CreateImageBitmapSupport {
4
- basic: boolean; // Supports createImageBitmap(image)
5
- options: boolean; // Supports createImageBitmap(image, options)
6
- full: boolean; // Supports createImageBitmap(image, sx, sy, sw, sh, options)
7
- }
8
-
9
- export async function validateCreateImageBitmap(
10
- platform: Platform,
11
- ): Promise<CreateImageBitmapSupport> {
12
- // Test if createImageBitmap is supported using a simple 1x1 PNG image
13
- // prettier-ignore
14
- const pngBinaryData = new Uint8Array([
15
- 0x89, 0x50, 0x4e, 0x47,
16
- 0x0d, 0x0a, 0x1a, 0x0a, // PNG signature
17
- 0x00, 0x00, 0x00, 0x0d, // IHDR chunk length
18
- 0x49, 0x48, 0x44, 0x52, // "IHDR" chunk type
19
- 0x00, 0x00, 0x00, 0x01, // Width: 1
20
- 0x00, 0x00, 0x00, 0x01, // Height: 1
21
- 0x01, // Bit depth: 1
22
- 0x03, // Color type: Indexed
23
- 0x00, // Compression method: Deflate
24
- 0x00, // Filter method: None
25
- 0x00, // Interlace method: None
26
- 0x25, 0xdb, 0x56, 0xca, // CRC for IHDR
27
- 0x00, 0x00, 0x00, 0x03, // PLTE chunk length
28
- 0x50, 0x4c, 0x54, 0x45, // "PLTE" chunk type
29
- 0x00, 0x00, 0x00, // Palette entry: Black
30
- 0xa7, 0x7a, 0x3d, 0xda, // CRC for PLTE
31
- 0x00, 0x00, 0x00, 0x01, // tRNS chunk length
32
- 0x74, 0x52, 0x4e, 0x53, // "tRNS" chunk type
33
- 0x00, // Transparency for black: Fully transparent
34
- 0x40, 0xe6, 0xd8, 0x66, // CRC for tRNS
35
- 0x00, 0x00, 0x00, 0x0a, // IDAT chunk length
36
- 0x49, 0x44, 0x41, 0x54, // "IDAT" chunk type
37
- 0x08, 0xd7, // Deflate header
38
- 0x63, 0x60, 0x00, 0x00,
39
- 0x00, 0x02, 0x00, 0x01, // Zlib-compressed data
40
- 0xe2, 0x21, 0xbc, 0x33, // CRC for IDAT
41
- 0x00, 0x00, 0x00, 0x00, // IEND chunk length
42
- 0x49, 0x45, 0x4e, 0x44, // "IEND" chunk type
43
- 0xae, 0x42, 0x60, 0x82, // CRC for IEND
44
- ]);
45
-
46
- const support: CreateImageBitmapSupport = {
47
- basic: false,
48
- options: false,
49
- full: false,
50
- };
51
-
52
- // Test basic createImageBitmap support
53
- const blob = new Blob([pngBinaryData], { type: 'image/png' });
54
- const bitmap = await platform.createImageBitmap(blob);
55
- bitmap.close?.();
56
- support.basic = true;
57
-
58
- // Test createImageBitmap with options support
59
- try {
60
- const options = { premultiplyAlpha: 'none' as const };
61
- const bitmapWithOptions = await platform.createImageBitmap(blob, options);
62
- bitmapWithOptions.close?.();
63
- support.options = true;
64
- } catch (e) {
65
- /* ignore */
66
- }
67
-
68
- // Test createImageBitmap with full options support
69
- try {
70
- const bitmapWithFullOptions = await platform.createImageBitmap(
71
- blob,
72
- 0,
73
- 0,
74
- 1,
75
- 1,
76
- {
77
- premultiplyAlpha: 'none',
78
- },
79
- );
80
- bitmapWithFullOptions.close?.();
81
- support.full = true;
82
- } catch (e) {
83
- /* ignore */
84
- }
85
-
86
- return support;
87
- }