@lightningjs/renderer 1.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +17 -0
  2. package/dist/exports/canvas.d.ts +20 -0
  3. package/dist/exports/canvas.js +39 -0
  4. package/dist/exports/canvas.js.map +1 -0
  5. package/dist/exports/index.d.ts +3 -5
  6. package/dist/exports/index.js +2 -4
  7. package/dist/exports/index.js.map +1 -1
  8. package/dist/exports/inspector.d.ts +4 -0
  9. package/dist/exports/inspector.js +23 -0
  10. package/dist/exports/inspector.js.map +1 -0
  11. package/dist/exports/utils.d.ts +2 -0
  12. package/dist/exports/utils.js +2 -0
  13. package/dist/exports/utils.js.map +1 -1
  14. package/dist/exports/webgl.d.ts +19 -0
  15. package/dist/exports/webgl.js +38 -0
  16. package/dist/exports/webgl.js.map +1 -0
  17. package/dist/src/common/EventEmitter.d.ts +1 -1
  18. package/dist/src/common/IAnimationController.d.ts +1 -1
  19. package/dist/src/common/IEventEmitter.d.ts +8 -0
  20. package/dist/src/common/IEventEmitter.js +18 -0
  21. package/dist/src/common/IEventEmitter.js.map +1 -0
  22. package/dist/src/core/CoreNode.d.ts +66 -2
  23. package/dist/src/core/CoreNode.js +128 -24
  24. package/dist/src/core/CoreNode.js.map +1 -1
  25. package/dist/src/core/CoreTextNode.d.ts +2 -2
  26. package/dist/src/core/CoreTextNode.js +20 -30
  27. package/dist/src/core/CoreTextNode.js.map +1 -1
  28. package/dist/src/core/Stage.d.ts +11 -5
  29. package/dist/src/core/Stage.js +58 -30
  30. package/dist/src/core/Stage.js.map +1 -1
  31. package/dist/src/core/TextureMemoryManager.js +4 -2
  32. package/dist/src/core/TextureMemoryManager.js.map +1 -1
  33. package/dist/src/core/animations/CoreAnimation.js +1 -1
  34. package/dist/src/core/animations/CoreAnimation.js.map +1 -1
  35. package/dist/src/core/lib/ImageWorker.d.ts +1 -1
  36. package/dist/src/core/lib/ImageWorker.js +25 -3
  37. package/dist/src/core/lib/ImageWorker.js.map +1 -1
  38. package/dist/src/core/lib/textureSvg.d.ts +16 -0
  39. package/dist/src/core/lib/textureSvg.js +63 -0
  40. package/dist/src/core/lib/textureSvg.js.map +1 -0
  41. package/dist/src/core/renderers/canvas/CanvasCoreTexture.js +2 -1
  42. package/dist/src/core/renderers/canvas/CanvasCoreTexture.js.map +1 -1
  43. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +2 -1
  44. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
  45. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +10 -6
  46. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
  47. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js +2 -1
  48. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js.map +1 -1
  49. package/dist/src/core/text-rendering/TrFontManager.js +11 -4
  50. package/dist/src/core/text-rendering/TrFontManager.js.map +1 -1
  51. package/dist/src/core/text-rendering/font-face-types/WebTrFontFace.js +13 -5
  52. package/dist/src/core/text-rendering/font-face-types/WebTrFontFace.js.map +1 -1
  53. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.d.ts +1 -0
  54. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +1 -0
  55. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
  56. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.d.ts +1 -0
  57. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +1 -0
  58. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
  59. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +1 -0
  60. package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
  61. package/dist/src/core/textures/ImageTexture.d.ts +52 -0
  62. package/dist/src/core/textures/ImageTexture.js +78 -31
  63. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  64. package/dist/src/core/textures/Texture.d.ts +1 -0
  65. package/dist/src/core/textures/Texture.js +1 -0
  66. package/dist/src/core/textures/Texture.js.map +1 -1
  67. package/dist/src/main-api/Inspector.js +2 -2
  68. package/dist/src/main-api/Inspector.js.map +1 -1
  69. package/dist/src/main-api/Renderer.d.ts +50 -8
  70. package/dist/src/main-api/Renderer.js +8 -7
  71. package/dist/src/main-api/Renderer.js.map +1 -1
  72. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  73. package/dist/tsconfig.tsbuildinfo +1 -0
  74. package/exports/canvas.ts +39 -0
  75. package/exports/index.ts +4 -4
  76. package/exports/inspector.ts +24 -0
  77. package/exports/utils.ts +2 -0
  78. package/exports/webgl.ts +38 -0
  79. package/package.json +5 -7
  80. package/src/common/EventEmitter.ts +1 -1
  81. package/src/common/IAnimationController.ts +1 -1
  82. package/src/common/IEventEmitter.ts +28 -0
  83. package/src/core/CoreNode.test.ts +1 -0
  84. package/src/core/CoreNode.ts +229 -40
  85. package/src/core/CoreTextNode.ts +58 -65
  86. package/src/core/Stage.ts +92 -40
  87. package/src/core/TextureMemoryManager.ts +4 -2
  88. package/src/core/animations/CoreAnimation.ts +2 -1
  89. package/src/core/lib/ImageWorker.ts +44 -7
  90. package/src/core/lib/textureSvg.ts +78 -0
  91. package/src/core/renderers/canvas/CanvasCoreTexture.ts +4 -1
  92. package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +2 -1
  93. package/src/core/renderers/webgl/WebGlCoreRenderer.ts +11 -6
  94. package/src/core/renderers/webgl/shaders/DynamicShader.ts +1 -0
  95. package/src/core/text-rendering/TrFontManager.ts +15 -4
  96. package/src/core/text-rendering/font-face-types/WebTrFontFace.ts +15 -8
  97. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +2 -0
  98. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +2 -0
  99. package/src/core/text-rendering/renderers/TextRenderer.ts +1 -0
  100. package/src/core/textures/ImageTexture.ts +159 -35
  101. package/src/core/textures/Texture.ts +2 -0
  102. package/src/main-api/Inspector.ts +2 -2
  103. package/src/main-api/Renderer.ts +59 -15
@@ -24,6 +24,7 @@ import {
24
24
  loadCompressedTexture,
25
25
  } from '../lib/textureCompression.js';
26
26
  import { convertUrlToAbsolute } from '../lib/utils.js';
27
+ import { isSvgImage, loadSvg } from '../lib/textureSvg.js';
27
28
 
28
29
  /**
29
30
  * Properties of the {@link ImageTexture}
@@ -55,6 +56,52 @@ export interface ImageTextureProps {
55
56
  * `ImageData` textures are not cached unless a `key` is provided
56
57
  */
57
58
  key?: string | null;
59
+ /**
60
+ * Width of the image to be used as a texture. If not provided, the image's
61
+ * natural width will be used.
62
+ */
63
+ width?: number | null;
64
+ /**
65
+ * Height of the image to be used as a texture. If not provided, the image's
66
+ * natural height will be used.
67
+ */
68
+ height?: number | null;
69
+ /**
70
+ * Type, indicate an image type for overriding type detection
71
+ *
72
+ * @default null
73
+ */
74
+ type?: 'regular' | 'compressed' | 'svg' | null;
75
+ /**
76
+ * The width of the rectangle from which the ImageBitmap will be extracted. This value
77
+ * can be negative. Only works when createImageBitmap is supported on the browser.
78
+ *
79
+ * @default null
80
+ */
81
+ sw?: number | null;
82
+ /**
83
+ * The height of the rectangle from which the ImageBitmap will be extracted. This value
84
+ * can be negative. Only works when createImageBitmap is supported on the browser.
85
+ *
86
+ * @default null
87
+ */
88
+ sh?: number | null;
89
+ /**
90
+ * The y coordinate of the reference point of the rectangle from which the ImageBitmap
91
+ * will be extracted. Only used when `sw` and `sh` are provided. And only works when
92
+ * createImageBitmap is available.
93
+ *
94
+ * @default null
95
+ */
96
+ sx?: number | null;
97
+ /**
98
+ * The x coordinate of the reference point of the rectangle from which the
99
+ * ImageBitmap will be extracted. Only used when source `sw` width and `sh` height
100
+ * are provided. Only works when createImageBitmap is supported on the browser.
101
+ *
102
+ * @default null
103
+ */
104
+ sy?: number | null;
58
105
  }
59
106
 
60
107
  /**
@@ -83,45 +130,35 @@ export class ImageTexture extends Texture {
83
130
  return mimeType.indexOf('image/png') !== -1;
84
131
  }
85
132
 
86
- override async getTextureData(): Promise<TextureData> {
87
- const { src, premultiplyAlpha } = this.props;
88
- if (!src) {
89
- return {
90
- data: null,
91
- };
92
- }
93
-
94
- if (typeof src !== 'string') {
95
- if (src instanceof ImageData) {
96
- return {
97
- data: src,
98
- premultiplyAlpha,
99
- };
100
- }
101
- return {
102
- data: src(),
103
- premultiplyAlpha,
104
- };
105
- }
106
-
107
- // Handle compressed textures
108
- if (isCompressedTextureContainer(src)) {
109
- return loadCompressedTexture(src);
110
- }
133
+ async loadImage(src: string) {
134
+ const { premultiplyAlpha, sx, sy, sw, sh, width, height } = this.props;
111
135
 
112
- // Convert relative URL to absolute URL
113
- const absoluteSrc = convertUrlToAbsolute(src);
114
-
115
- if (this.txManager.imageWorkerManager) {
136
+ if (this.txManager.imageWorkerManager !== null) {
116
137
  return await this.txManager.imageWorkerManager.getImage(
117
- absoluteSrc,
138
+ src,
118
139
  premultiplyAlpha,
140
+ sx,
141
+ sy,
142
+ sw,
143
+ sh,
119
144
  );
120
- } else if (this.txManager.hasCreateImageBitmap) {
121
- const response = await fetch(absoluteSrc);
145
+ } else if (this.txManager.hasCreateImageBitmap === true) {
146
+ const response = await fetch(src);
122
147
  const blob = await response.blob();
123
148
  const hasAlphaChannel =
124
149
  premultiplyAlpha ?? this.hasAlphaChannel(blob.type);
150
+
151
+ if (sw !== null && sh !== null) {
152
+ return {
153
+ data: await createImageBitmap(blob, sx ?? 0, sy ?? 0, sw, sh, {
154
+ premultiplyAlpha: hasAlphaChannel ? 'premultiply' : 'none',
155
+ colorSpaceConversion: 'none',
156
+ imageOrientation: 'none',
157
+ }),
158
+ premultiplyAlpha: hasAlphaChannel,
159
+ };
160
+ }
161
+
125
162
  return {
126
163
  data: await createImageBitmap(blob, {
127
164
  premultiplyAlpha: hasAlphaChannel ? 'premultiply' : 'none',
@@ -131,11 +168,11 @@ export class ImageTexture extends Texture {
131
168
  premultiplyAlpha: hasAlphaChannel,
132
169
  };
133
170
  } else {
134
- const img = new Image();
171
+ const img = new Image(width || undefined, height || undefined);
135
172
  if (!(src.substr(0, 5) === 'data:')) {
136
173
  img.crossOrigin = 'Anonymous';
137
174
  }
138
- img.src = absoluteSrc;
175
+ img.src = src;
139
176
  await new Promise<void>((resolve, reject) => {
140
177
  img.onload = () => resolve();
141
178
  img.onerror = () => reject(new Error(`Failed to load image`));
@@ -150,6 +187,73 @@ export class ImageTexture extends Texture {
150
187
  }
151
188
  }
152
189
 
190
+ override async getTextureData(): Promise<TextureData> {
191
+ const { src, premultiplyAlpha, type } = this.props;
192
+ if (src === null) {
193
+ return {
194
+ data: null,
195
+ };
196
+ }
197
+
198
+ if (typeof src !== 'string') {
199
+ if (src instanceof ImageData) {
200
+ return {
201
+ data: src,
202
+ premultiplyAlpha,
203
+ };
204
+ }
205
+ return {
206
+ data: src(),
207
+ premultiplyAlpha,
208
+ };
209
+ }
210
+
211
+ const absoluteSrc = convertUrlToAbsolute(src);
212
+ if (type === 'regular') {
213
+ return this.loadImage(absoluteSrc);
214
+ }
215
+
216
+ if (type === 'svg') {
217
+ return loadSvg(
218
+ absoluteSrc,
219
+ this.props.width,
220
+ this.props.height,
221
+ this.props.sx,
222
+ this.props.sy,
223
+ this.props.sw,
224
+ this.props.sh,
225
+ );
226
+ }
227
+
228
+ if (isSvgImage(src) === true) {
229
+ return loadSvg(
230
+ absoluteSrc,
231
+ this.props.width,
232
+ this.props.height,
233
+ this.props.sx,
234
+ this.props.sy,
235
+ this.props.sw,
236
+ this.props.sh,
237
+ );
238
+ }
239
+
240
+ if (type === 'compressed') {
241
+ return loadCompressedTexture(absoluteSrc);
242
+ }
243
+
244
+ if (isCompressedTextureContainer(src) === true) {
245
+ return loadCompressedTexture(absoluteSrc);
246
+ }
247
+
248
+ // default
249
+ return this.loadImage(absoluteSrc);
250
+ }
251
+
252
+ /**
253
+ * Generates a cache key for the ImageTexture based on the provided props.
254
+ * @param props - The props used to generate the cache key.
255
+ * @returns The cache key as a string, or `false` if the key cannot be generated.
256
+ */
153
257
  static override makeCacheKey(props: ImageTextureProps): string | false {
154
258
  const resolvedProps = ImageTexture.resolveDefaults(props);
155
259
  // Only cache key-able textures; prioritise key
@@ -157,7 +261,20 @@ export class ImageTexture extends Texture {
157
261
  if (typeof key !== 'string') {
158
262
  return false;
159
263
  }
160
- return `ImageTexture,${key},${resolvedProps.premultiplyAlpha ?? 'true'}`;
264
+
265
+ // if we have source dimensions, cache the texture separately
266
+ let dimensionProps = '';
267
+ if (resolvedProps.sh !== null && resolvedProps.sw !== null) {
268
+ dimensionProps += ',';
269
+ dimensionProps += resolvedProps.sx ?? '';
270
+ dimensionProps += resolvedProps.sy ?? '';
271
+ dimensionProps += resolvedProps.sw || '';
272
+ dimensionProps += resolvedProps.sh || '';
273
+ }
274
+
275
+ return `ImageTexture,${key},${
276
+ resolvedProps.premultiplyAlpha ?? 'true'
277
+ }${dimensionProps}`;
161
278
  }
162
279
 
163
280
  static override resolveDefaults(
@@ -167,6 +284,13 @@ export class ImageTexture extends Texture {
167
284
  src: props.src ?? '',
168
285
  premultiplyAlpha: props.premultiplyAlpha ?? true, // null,
169
286
  key: props.key ?? null,
287
+ type: props.type ?? null,
288
+ width: props.width ?? null,
289
+ height: props.height ?? null,
290
+ sx: props.sx ?? null,
291
+ sy: props.sy ?? null,
292
+ sw: props.sw ?? null,
293
+ sh: props.sh ?? null,
170
294
  };
171
295
  }
172
296
 
@@ -150,6 +150,8 @@ export abstract class Texture extends EventEmitter {
150
150
 
151
151
  readonly lastRenderableChangeTime = 0;
152
152
 
153
+ public preventCleanup = false;
154
+
153
155
  constructor(protected txManager: CoreTextureManager) {
154
156
  super();
155
157
  }
@@ -128,7 +128,7 @@ const convertColorToRgba = (color: number) => {
128
128
  };
129
129
 
130
130
  const domPropertyMap: { [key: string]: string } = {
131
- id: 'id',
131
+ id: 'test-id',
132
132
  };
133
133
 
134
134
  const gradientColorPropertyMap = [
@@ -163,7 +163,7 @@ export class Inspector {
163
163
  );
164
164
 
165
165
  this.width = Math.ceil(
166
- settings.appWidth ?? 1900 / (settings.deviceLogicalPixelRatio ?? 1),
166
+ settings.appWidth ?? 1920 / (settings.deviceLogicalPixelRatio ?? 1),
167
167
  );
168
168
 
169
169
  this.scaleX = settings.deviceLogicalPixelRatio ?? 1;
@@ -21,7 +21,6 @@
21
21
  import type { EffectMap, ShaderMap } from '../core/CoreShaderManager.js';
22
22
  import type { ExtractProps, TextureMap } from '../core/CoreTextureManager.js';
23
23
  import { EventEmitter } from '../common/EventEmitter.js';
24
- import { Inspector } from './Inspector.js';
25
24
  import { assertTruthy, isProductionEnvironment } from '../utils.js';
26
25
  import { Stage } from '../core/Stage.js';
27
26
  import { CoreNode, type CoreNodeProps } from '../core/CoreNode.js';
@@ -40,6 +39,11 @@ import type {
40
39
  EffectDescUnion,
41
40
  } from '../core/renderers/webgl/shaders/effects/ShaderEffect.js';
42
41
  import type { TextureMemoryManagerSettings } from '../core/TextureMemoryManager.js';
42
+ import type { CanvasTextRenderer } from '../core/text-rendering/renderers/CanvasTextRenderer.js';
43
+ import type { SdfTextRenderer } from '../core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js';
44
+ import type { WebGlCoreRenderer } from '../core/renderers/webgl/WebGlCoreRenderer.js';
45
+ import type { CanvasCoreRenderer } from '../core/renderers/canvas/CanvasCoreRenderer.js';
46
+ import type { Inspector } from './Inspector.js';
43
47
 
44
48
  /**
45
49
  * An immutable reference to a specific Shader type
@@ -181,21 +185,29 @@ export interface RendererMainSettings {
181
185
  numImageWorkers?: number;
182
186
 
183
187
  /**
184
- * Enable inspector
188
+ * DOM Inspector
185
189
  *
186
190
  * @remarks
187
- * When enabled the renderer will spawn a inspector. The inspector will
188
- * replicate the state of the Nodes created in the renderer and allow
189
- * inspection of the state of the nodes.
191
+ * The inspector will replicate the state of the Nodes created
192
+ * in the renderer and allow inspection of the state of the nodes.
190
193
  *
191
- * @defaultValue `false` (disabled)
192
194
  */
193
- enableInspector?: boolean;
195
+ inspector?: typeof Inspector | false;
194
196
 
195
197
  /**
196
- * Renderer mode
198
+ * Renderer Engine
199
+ *
200
+ * @remarks
201
+ * The renderer engine to use. Spawns a WebGL or Canvas renderer.
202
+ * WebGL is more performant and supports more features. Canvas is
203
+ * supported on most platforms.
204
+ *
205
+ * Note: When using CanvasCoreRenderer you can only use
206
+ * CanvasTextRenderer. The WebGLCoreRenderer supports
207
+ * both CanvasTextRenderer and SdfTextRenderer for Text Rendering.
208
+ *
197
209
  */
198
- renderMode?: 'webgl' | 'canvas';
210
+ renderEngine: typeof CanvasCoreRenderer | typeof WebGlCoreRenderer;
199
211
 
200
212
  /**
201
213
  * Quad buffer size in bytes
@@ -203,6 +215,36 @@ export interface RendererMainSettings {
203
215
  * @defaultValue 4 * 1024 * 1024
204
216
  */
205
217
  quadBufferSize?: number;
218
+
219
+ /**
220
+ * Font Engines
221
+ *
222
+ * @remarks
223
+ * The font engines to use for text rendering. CanvasTextRenderer is supported
224
+ * on all platforms. SdfTextRenderer is a more performant renderer.
225
+ * When using `renderEngine=CanvasCoreRenderer` you can only use `CanvasTextRenderer`.
226
+ * The `renderEngine=WebGLCoreRenderer` supports both `CanvasTextRenderer` and `SdfTextRenderer`.
227
+ *
228
+ * This setting is used to enable tree shaking of unused font engines. Please
229
+ * import your font engine(s) as follows:
230
+ * ```
231
+ * import { CanvasTextRenderer } from '@lightning/renderer/canvas';
232
+ * import { SdfTextRenderer } from '@lightning/renderer/webgl';
233
+ * ```
234
+ *
235
+ * If both CanvasTextRenderer and SdfTextRenderer are provided, the first renderer
236
+ * provided will be asked first if it can render the font. If it cannot render the
237
+ * font, the next renderer will be asked. If no renderer can render the font, the
238
+ * text will not be rendered.
239
+ *
240
+ * **Note** that if you have fonts available in both engines the second font engine
241
+ * will not be used. This is because the first font engine will always be asked first.
242
+ *
243
+ * @defaultValue '[]'
244
+ *
245
+ *
246
+ */
247
+ fontEngines: (typeof SdfTextRenderer | typeof CanvasTextRenderer)[];
206
248
  }
207
249
 
208
250
  /**
@@ -288,9 +330,10 @@ export class RendererMain extends EventEmitter {
288
330
  numImageWorkers:
289
331
  settings.numImageWorkers !== undefined ? settings.numImageWorkers : 2,
290
332
  enableContextSpy: settings.enableContextSpy ?? false,
291
- enableInspector: settings.enableInspector ?? false,
292
- renderMode: settings.renderMode ?? 'webgl',
333
+ inspector: settings.inspector ?? false,
334
+ renderEngine: settings.renderEngine,
293
335
  quadBufferSize: settings.quadBufferSize ?? 4 * 1024 * 1024,
336
+ fontEngines: settings.fontEngines,
294
337
  };
295
338
  this.settings = resolvedSettings;
296
339
 
@@ -299,7 +342,7 @@ export class RendererMain extends EventEmitter {
299
342
  appHeight,
300
343
  deviceLogicalPixelRatio,
301
344
  devicePhysicalPixelRatio,
302
- enableInspector,
345
+ inspector,
303
346
  } = resolvedSettings;
304
347
 
305
348
  const deviceLogicalWidth = appWidth * deviceLogicalPixelRatio;
@@ -325,10 +368,11 @@ export class RendererMain extends EventEmitter {
325
368
  enableContextSpy: this.settings.enableContextSpy,
326
369
  fpsUpdateInterval: this.settings.fpsUpdateInterval,
327
370
  numImageWorkers: this.settings.numImageWorkers,
328
- renderMode: this.settings.renderMode,
371
+ renderEngine: this.settings.renderEngine,
329
372
  textureMemory: resolvedTxSettings,
330
373
  eventBus: this,
331
374
  quadBufferSize: this.settings.quadBufferSize,
375
+ fontEngines: this.settings.fontEngines,
332
376
  });
333
377
 
334
378
  // Extract the root node
@@ -351,8 +395,8 @@ export class RendererMain extends EventEmitter {
351
395
  targetEl.appendChild(canvas);
352
396
 
353
397
  // Initialize inspector (if enabled)
354
- if (enableInspector && !isProductionEnvironment()) {
355
- this.inspector = new Inspector(canvas, resolvedSettings);
398
+ if (inspector && !isProductionEnvironment()) {
399
+ this.inspector = new inspector(canvas, resolvedSettings);
356
400
  }
357
401
  }
358
402