@lightningjs/renderer 0.9.1 → 0.9.2

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 (74) hide show
  1. package/dist/exports/index.d.ts +3 -0
  2. package/dist/{src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js → exports/index.js} +4 -11
  3. package/dist/exports/index.js.map +1 -0
  4. package/dist/src/common/IAnimationController.d.ts +58 -1
  5. package/dist/src/common/IAnimationController.js +0 -18
  6. package/dist/src/common/IAnimationController.js.map +1 -1
  7. package/dist/src/core/CoreTextureManager.js +1 -1
  8. package/dist/src/core/CoreTextureManager.js.map +1 -1
  9. package/dist/src/core/animations/CoreAnimation.d.ts +2 -2
  10. package/dist/src/core/animations/CoreAnimation.js +33 -10
  11. package/dist/src/core/animations/CoreAnimation.js.map +1 -1
  12. package/dist/src/core/animations/CoreAnimationController.d.ts +8 -12
  13. package/dist/src/core/animations/CoreAnimationController.js +42 -46
  14. package/dist/src/core/animations/CoreAnimationController.js.map +1 -1
  15. package/dist/src/core/lib/ImageWorker.js +8 -5
  16. package/dist/src/core/lib/ImageWorker.js.map +1 -1
  17. package/dist/src/core/textures/ImageTexture.d.ts +5 -1
  18. package/dist/src/core/textures/ImageTexture.js +14 -6
  19. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  20. package/dist/src/core/utils.js +1 -6
  21. package/dist/src/core/utils.js.map +1 -1
  22. package/dist/src/main-api/INode.d.ts +1 -1
  23. package/dist/src/main-api/Renderer.d.ts +297 -0
  24. package/dist/src/main-api/Renderer.js +370 -0
  25. package/dist/src/main-api/Renderer.js.map +1 -0
  26. package/dist/src/main-api/utils.d.ts +2 -0
  27. package/dist/src/main-api/utils.js +34 -0
  28. package/dist/src/main-api/utils.js.map +1 -0
  29. package/dist/src/render-drivers/threadx/ThreadXMainAnimationController.d.ts +8 -4
  30. package/dist/src/render-drivers/threadx/ThreadXMainAnimationController.js +53 -24
  31. package/dist/src/render-drivers/threadx/ThreadXMainAnimationController.js.map +1 -1
  32. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js +6 -0
  33. package/dist/src/render-drivers/threadx/worker/ThreadXRendererNode.js.map +1 -1
  34. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  35. package/{dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js → exports/index.ts} +4 -14
  36. package/package.json +1 -1
  37. package/src/common/IAnimationController.ts +60 -1
  38. package/src/core/CoreTextureManager.ts +1 -1
  39. package/src/core/animations/CoreAnimation.ts +35 -11
  40. package/src/core/animations/CoreAnimationController.ts +48 -53
  41. package/src/core/lib/ImageWorker.ts +10 -7
  42. package/src/core/textures/ImageTexture.ts +19 -6
  43. package/src/core/utils.ts +1 -7
  44. package/src/main-api/INode.ts +1 -1
  45. package/src/render-drivers/threadx/ThreadXMainAnimationController.ts +63 -27
  46. package/src/render-drivers/threadx/worker/ThreadXRendererNode.ts +6 -0
  47. package/dist/src/core/lib/WebGlContext.d.ts +0 -414
  48. package/dist/src/core/lib/WebGlContext.js +0 -640
  49. package/dist/src/core/lib/WebGlContext.js.map +0 -1
  50. package/dist/src/core/scene/Scene.d.ts +0 -59
  51. package/dist/src/core/scene/Scene.js +0 -106
  52. package/dist/src/core/scene/Scene.js.map +0 -1
  53. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.d.ts +0 -8
  54. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js.map +0 -1
  55. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.d.ts +0 -19
  56. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js +0 -84
  57. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js.map +0 -1
  58. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.d.ts +0 -8
  59. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js +0 -40
  60. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js.map +0 -1
  61. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.d.ts +0 -2
  62. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js +0 -41
  63. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js.map +0 -1
  64. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.d.ts +0 -1
  65. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js +0 -4
  66. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js.map +0 -1
  67. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.d.ts +0 -1
  68. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js +0 -2
  69. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js.map +0 -1
  70. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.d.ts +0 -20
  71. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.js +0 -55
  72. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.js.map +0 -1
  73. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.d.ts +0 -9
  74. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js.map +0 -1
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/unbound-method */
1
2
  /*
2
3
  * If not stated otherwise in this file or this component's LICENSE file the
3
4
  * following copyright and licenses apply:
@@ -24,50 +25,48 @@ import type {
24
25
  import type { AnimationManager } from './AnimationManager.js';
25
26
  import type { CoreAnimation } from './CoreAnimation.js';
26
27
  import { assertTruthy } from '../../utils.js';
28
+ import { EventEmitter } from '../../common/EventEmitter.js';
27
29
 
28
- export class CoreAnimationController implements IAnimationController {
29
- startedPromise: Promise<void> | null = null;
30
- /**
31
- * If this is null, then the animation hasn't started yet.
32
- */
33
- startedResolve: ((scope?: any) => void) | null = null;
34
-
35
- stoppedPromise: Promise<void> | null = null;
30
+ export class CoreAnimationController
31
+ extends EventEmitter
32
+ implements IAnimationController
33
+ {
34
+ stoppedPromise: Promise<void>;
36
35
  /**
37
36
  * If this is null, then the animation is in a finished / stopped state.
38
37
  */
39
38
  stoppedResolve: (() => void) | null = null;
39
+ state: AnimationControllerState;
40
40
 
41
41
  constructor(
42
42
  private manager: AnimationManager,
43
43
  private animation: CoreAnimation,
44
44
  ) {
45
+ super();
45
46
  this.state = 'stopped';
46
- }
47
+ // Initial stopped promise is resolved (since the animation is stopped)
48
+ this.stoppedPromise = Promise.resolve();
47
49
 
48
- state: AnimationControllerState;
50
+ // Bind event handlers
51
+ this.onAnimating = this.onAnimating.bind(this);
52
+ this.onFinished = this.onFinished.bind(this);
53
+ }
49
54
 
50
55
  start(): IAnimationController {
51
- this.makeStartedPromise();
52
- this.animation.once('start', this.started.bind(this));
53
-
54
- this.makeStoppedPromise();
55
- this.animation.once('finished', this.finished.bind(this));
56
-
57
- // prevent registering the same animation twice
58
- if (!this.manager.activeAnimations.has(this.animation)) {
59
- this.manager.registerAnimation(this.animation);
56
+ if (this.state !== 'running') {
57
+ this.makeStoppedPromise();
58
+ this.registerAnimation();
59
+ this.state = 'running';
60
60
  }
61
-
62
- this.state = 'running';
63
61
  return this;
64
62
  }
65
63
 
66
64
  stop(): IAnimationController {
67
- this.manager.unregisterAnimation(this.animation);
65
+ this.unregisterAnimation();
68
66
  if (this.stoppedResolve !== null) {
69
67
  this.stoppedResolve();
70
68
  this.stoppedResolve = null;
69
+ this.emit('stopped', this);
71
70
  }
72
71
  this.animation.reset();
73
72
  this.state = 'stopped';
@@ -75,7 +74,7 @@ export class CoreAnimationController implements IAnimationController {
75
74
  }
76
75
 
77
76
  pause(): IAnimationController {
78
- this.manager.unregisterAnimation(this.animation);
77
+ this.unregisterAnimation();
79
78
  this.state = 'paused';
80
79
  return this;
81
80
  }
@@ -86,26 +85,24 @@ export class CoreAnimationController implements IAnimationController {
86
85
  return this;
87
86
  }
88
87
 
89
- waitUntilStarted(): Promise<void> {
90
- this.makeStartedPromise();
91
- const promise = this.startedPromise;
92
- assertTruthy(promise);
93
- return promise;
88
+ waitUntilStopped(): Promise<void> {
89
+ return this.stoppedPromise;
94
90
  }
95
91
 
96
- waitUntilStopped(): Promise<void> {
97
- this.makeStoppedPromise();
98
- const promise = this.stoppedPromise;
99
- assertTruthy(promise);
100
- return promise;
92
+ private registerAnimation(): void {
93
+ // Hook up event listeners
94
+ this.animation.once('finished', this.onFinished);
95
+ this.animation.on('animating', this.onAnimating);
96
+ // Then register the animation
97
+ this.manager.registerAnimation(this.animation);
101
98
  }
102
99
 
103
- private makeStartedPromise(): void {
104
- if (this.startedResolve === null) {
105
- this.startedPromise = new Promise((resolve) => {
106
- this.startedResolve = resolve;
107
- });
108
- }
100
+ private unregisterAnimation(): void {
101
+ // First unregister the animation
102
+ this.manager.unregisterAnimation(this.animation);
103
+ // Then unhook event listeners
104
+ this.animation.off('finished', this.onFinished);
105
+ this.animation.off('animating', this.onAnimating);
109
106
  }
110
107
 
111
108
  private makeStoppedPromise(): void {
@@ -116,33 +113,31 @@ export class CoreAnimationController implements IAnimationController {
116
113
  }
117
114
  }
118
115
 
119
- private started(): void {
120
- assertTruthy(this.startedResolve);
121
- // resolve promise (and pass current this to continue to the chain)
122
- this.startedResolve(this);
123
- this.startedResolve = null;
124
- }
125
-
126
- private finished(): void {
116
+ private onFinished(this: CoreAnimationController): void {
127
117
  assertTruthy(this.stoppedResolve);
128
118
  // If the animation is looping, then we need to restart it.
129
119
  const { loop, stopMethod } = this.animation.settings;
130
120
 
131
121
  if (stopMethod === 'reverse') {
132
122
  this.animation.reverse();
133
- this.start();
134
123
  return;
135
124
  }
136
125
 
137
- // resolve promise
138
- this.stoppedResolve();
139
- this.stoppedResolve = null;
140
-
141
126
  if (loop) {
142
127
  return;
143
128
  }
144
129
 
145
130
  // unregister animation
146
- this.manager.unregisterAnimation(this.animation);
131
+ this.unregisterAnimation();
132
+
133
+ // resolve promise
134
+ this.stoppedResolve();
135
+ this.stoppedResolve = null;
136
+ this.emit('stopped', this);
137
+ this.state = 'stopped';
138
+ }
139
+
140
+ private onAnimating(this: CoreAnimationController): void {
141
+ this.emit('animating', this);
147
142
  }
148
143
  }
@@ -119,10 +119,10 @@ export class ImageWorkerManager {
119
119
  return workers;
120
120
  }
121
121
 
122
- private getNextWorker(): Worker {
122
+ private getNextWorker(): Worker | undefined {
123
123
  const worker = this.workers[this.workerIndex];
124
124
  this.workerIndex = (this.workerIndex + 1) % this.workers.length;
125
- return worker!;
125
+ return worker;
126
126
  }
127
127
 
128
128
  private convertUrlToAbsolute(url: string): string {
@@ -140,11 +140,14 @@ export class ImageWorkerManager {
140
140
  const absoluteSrcUrl = this.convertUrlToAbsolute(src);
141
141
  const id = this.nextId++;
142
142
  this.messageManager[id] = [resolve, reject];
143
- this.getNextWorker().postMessage({
144
- id,
145
- src: absoluteSrcUrl,
146
- premultiplyAlpha,
147
- });
143
+ const nextWorker = this.getNextWorker();
144
+ if (nextWorker) {
145
+ nextWorker.postMessage({
146
+ id,
147
+ src: absoluteSrcUrl,
148
+ premultiplyAlpha,
149
+ });
150
+ }
148
151
  }
149
152
  } catch (error) {
150
153
  reject(error);
@@ -37,7 +37,7 @@ export interface ImageTextureProps {
37
37
  *
38
38
  * @default ''
39
39
  */
40
- src?: string | ImageData;
40
+ src?: string | ImageData | (() => ImageData);
41
41
  /**
42
42
  * Whether to premultiply the alpha channel into the color channels of the
43
43
  * image.
@@ -50,6 +50,10 @@ export interface ImageTextureProps {
50
50
  * @default true
51
51
  */
52
52
  premultiplyAlpha?: boolean | null;
53
+ /**
54
+ * `ImageData` textures are not cached unless a `key` is provided
55
+ */
56
+ key?: string | null;
53
57
  }
54
58
 
55
59
  /**
@@ -85,9 +89,16 @@ export class ImageTexture extends Texture {
85
89
  data: null,
86
90
  };
87
91
  }
88
- if (src instanceof ImageData) {
92
+
93
+ if (typeof src !== 'string') {
94
+ if (src instanceof ImageData) {
95
+ return {
96
+ data: src,
97
+ premultiplyAlpha,
98
+ };
99
+ }
89
100
  return {
90
- data: src,
101
+ data: src(),
91
102
  premultiplyAlpha,
92
103
  };
93
104
  }
@@ -137,11 +148,12 @@ export class ImageTexture extends Texture {
137
148
 
138
149
  static override makeCacheKey(props: ImageTextureProps): string | false {
139
150
  const resolvedProps = ImageTexture.resolveDefaults(props);
140
- // ImageTextures sourced by ImageData are non-cacheable
141
- if (resolvedProps.src instanceof ImageData) {
151
+ // Only cache key-able textures; prioritise key
152
+ const key = resolvedProps.key || resolvedProps.src;
153
+ if (typeof key !== 'string') {
142
154
  return false;
143
155
  }
144
- return `ImageTexture,${resolvedProps.src},${resolvedProps.premultiplyAlpha}`;
156
+ return `ImageTexture,${key},${resolvedProps.premultiplyAlpha ?? 'true'}`;
145
157
  }
146
158
 
147
159
  static override resolveDefaults(
@@ -150,6 +162,7 @@ export class ImageTexture extends Texture {
150
162
  return {
151
163
  src: props.src ?? '',
152
164
  premultiplyAlpha: props.premultiplyAlpha ?? true, // null,
165
+ key: props.key ?? null
153
166
  };
154
167
  }
155
168
 
package/src/core/utils.ts CHANGED
@@ -177,7 +177,7 @@ const parseCubicBezier = (str: string) => {
177
177
  export const getTimingFunction = (
178
178
  str: string,
179
179
  ): ((time: number) => number | undefined) => {
180
- if (str === '') {
180
+ if (str === 'linear') {
181
181
  return defaultTiming;
182
182
  }
183
183
 
@@ -185,12 +185,6 @@ export const getTimingFunction = (
185
185
  return timingMapping[str] || defaultTiming;
186
186
  }
187
187
 
188
- if (str === 'linear') {
189
- return (time: number) => {
190
- return time;
191
- };
192
- }
193
-
194
188
  if (str === 'step-start') {
195
189
  return () => {
196
190
  return 1;
@@ -443,7 +443,7 @@ export interface INodeWritableProps {
443
443
  * The data stored can only be of type string, number or boolean.
444
444
  */
445
445
  export type CustomDataMap = {
446
- [key: string]: string | number | boolean;
446
+ [key: string]: string | number | boolean | undefined;
447
447
  };
448
448
 
449
449
  export type INodeAnimatableProps = {
@@ -18,6 +18,7 @@
18
18
  */
19
19
 
20
20
  /* eslint-disable @typescript-eslint/unbound-method */
21
+ import { EventEmitter } from '../../common/EventEmitter.js';
21
22
  import type {
22
23
  AnimationControllerState,
23
24
  IAnimationController,
@@ -25,37 +26,48 @@ import type {
25
26
  import { assertTruthy } from '../../utils.js';
26
27
  import type { ThreadXMainNode } from './ThreadXMainNode.js';
27
28
 
28
- export class ThreadXMainAnimationController implements IAnimationController {
29
- stoppedPromise: Promise<void> | null = null;
29
+ export class ThreadXMainAnimationController
30
+ extends EventEmitter
31
+ implements IAnimationController
32
+ {
33
+ stoppedPromise: Promise<void>;
30
34
  /**
31
35
  * If this is null, then the animation is in a finished / stopped state.
32
36
  */
33
37
  stoppedResolve: (() => void) | null = null;
38
+ state: AnimationControllerState;
34
39
 
35
40
  constructor(private node: ThreadXMainNode, private id: number) {
36
- this.onAnimationFinished = this.onAnimationFinished.bind(this);
41
+ super();
37
42
  this.state = 'stopped';
38
- }
39
43
 
40
- state: AnimationControllerState;
44
+ // Initial stopped promise is resolved (since the animation is stopped)
45
+ this.stoppedPromise = Promise.resolve();
46
+
47
+ // Bind event handlers
48
+ this.onAnimating = this.onAnimating.bind(this);
49
+ this.onFinished = this.onFinished.bind(this);
50
+ }
41
51
 
42
52
  start(): IAnimationController {
43
- if (this.stoppedResolve === null) {
53
+ if (this.state !== 'running') {
44
54
  this.makeStoppedPromise();
45
- this.node.on('animationFinished', this.onAnimationFinished);
55
+ this.sendStart();
56
+ this.state = 'running';
46
57
  }
47
- this.state = 'running';
48
- this.node.emit('startAnimation', { id: this.id });
49
58
  return this;
50
59
  }
51
60
 
52
61
  stop(): IAnimationController {
53
- this.node.emit('stopAnimation', { id: this.id });
54
- this.node.off('animationFinished', this.onAnimationFinished);
55
- if (this.stoppedResolve !== null) {
56
- this.stoppedResolve();
57
- this.stoppedResolve = null;
62
+ if (this.state === 'stopped') {
63
+ return this;
58
64
  }
65
+ this.sendStop();
66
+ // if (this.stoppedResolve !== null) {
67
+ // this.stoppedResolve();
68
+ // this.stoppedResolve = null;
69
+ // this.emit('stopped', this);
70
+ // }
59
71
  this.state = 'stopped';
60
72
  return this;
61
73
  }
@@ -71,29 +83,53 @@ export class ThreadXMainAnimationController implements IAnimationController {
71
83
  }
72
84
 
73
85
  waitUntilStopped(): Promise<void> {
74
- this.makeStoppedPromise();
75
- const promise = this.stoppedPromise;
76
- assertTruthy(promise);
77
- return promise;
86
+ return this.stoppedPromise;
87
+ }
88
+
89
+ private sendStart(): void {
90
+ // Hook up event listeners
91
+ this.node.on('animationFinished', this.onFinished);
92
+ this.node.on('animationAnimating', this.onAnimating);
93
+ // Then register the animation
94
+ this.node.emit('startAnimation', { id: this.id });
95
+ }
96
+
97
+ private sendStop(): void {
98
+ // First unregister the animation
99
+ this.node.emit('stopAnimation', { id: this.id });
100
+ // Then unhook event listeners
101
+ this.node.off('animationFinished', this.onFinished);
102
+ this.node.off('animationAnimating', this.onAnimating);
78
103
  }
79
104
 
80
- private onAnimationFinished(
105
+ private makeStoppedPromise(): void {
106
+ if (this.stoppedResolve === null) {
107
+ this.stoppedPromise = new Promise((resolve) => {
108
+ this.stoppedResolve = resolve;
109
+ });
110
+ }
111
+ }
112
+
113
+ private onFinished(
81
114
  target: ThreadXMainNode,
82
- { id, loop }: { id: number; loop: boolean },
115
+ { id }: { id: number; loop: boolean },
83
116
  ) {
84
117
  if (id === this.id) {
85
- this.node.off('animationFinished', this.onAnimationFinished);
86
- this.stoppedResolve?.();
118
+ assertTruthy(this.stoppedResolve);
119
+ this.node.off('animationFinished', this.onFinished);
120
+ this.node.off('animationAnimating', this.onAnimating);
121
+
122
+ // resolve promise
123
+ this.stoppedResolve();
87
124
  this.stoppedResolve = null;
125
+ this.emit('stopped', this);
88
126
  this.state = 'stopped';
89
127
  }
90
128
  }
91
129
 
92
- private makeStoppedPromise(): void {
93
- if (this.stoppedResolve === null) {
94
- this.stoppedPromise = new Promise((resolve) => {
95
- this.stoppedResolve = resolve;
96
- });
130
+ private onAnimating(target: ThreadXMainNode, { id }: { id: number }) {
131
+ if (id === this.id) {
132
+ this.emit('animating', this);
97
133
  }
98
134
  }
99
135
  }
@@ -84,6 +84,12 @@ export class ThreadXRendererNode extends SharedNode {
84
84
  props as Partial<INodeAnimatableProps>,
85
85
  settings as Partial<AnimationSettings>,
86
86
  );
87
+ animation.on('animating', () => {
88
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
89
+ this.emit('animationAnimating', {
90
+ id: id as number,
91
+ });
92
+ });
87
93
  animation.on('finished', () => {
88
94
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
89
95
  this.emit('animationFinished', {