@lightningjs/renderer 0.7.5 → 0.7.6

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 (218) hide show
  1. package/LICENSE +202 -202
  2. package/NOTICE +3 -3
  3. package/README.md +229 -221
  4. package/dist/src/common/CommonTypes.d.ts +6 -0
  5. package/dist/src/core/CoreNode.d.ts +21 -4
  6. package/dist/src/core/CoreNode.js +145 -34
  7. package/dist/src/core/CoreNode.js.map +1 -1
  8. package/dist/src/core/CoreTextNode.d.ts +1 -1
  9. package/dist/src/core/CoreTextNode.js +18 -10
  10. package/dist/src/core/CoreTextNode.js.map +1 -1
  11. package/dist/src/core/CoreTextureManager.d.ts +3 -1
  12. package/dist/src/core/CoreTextureManager.js +9 -2
  13. package/dist/src/core/CoreTextureManager.js.map +1 -1
  14. package/dist/src/core/Stage.d.ts +2 -0
  15. package/dist/src/core/Stage.js +9 -1
  16. package/dist/src/core/Stage.js.map +1 -1
  17. package/dist/src/core/lib/ImageWorker.d.ts +0 -1
  18. package/dist/src/core/lib/ImageWorker.js +55 -40
  19. package/dist/src/core/lib/ImageWorker.js.map +1 -1
  20. package/dist/src/core/lib/RenderCoords.d.ts +13 -0
  21. package/dist/src/core/lib/RenderCoords.js +63 -0
  22. package/dist/src/core/lib/RenderCoords.js.map +1 -0
  23. package/dist/src/core/lib/WebGlContext.d.ts +414 -0
  24. package/dist/src/core/lib/WebGlContext.js +640 -0
  25. package/dist/src/core/lib/WebGlContext.js.map +1 -0
  26. package/dist/src/core/lib/utils.d.ts +1 -0
  27. package/dist/src/core/lib/utils.js +6 -0
  28. package/dist/src/core/lib/utils.js.map +1 -1
  29. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js +4 -1
  30. package/dist/src/core/renderers/webgl/WebGlCoreCtxTexture.js.map +1 -1
  31. package/dist/src/core/renderers/webgl/internal/RendererUtils.d.ts +9 -0
  32. package/dist/src/core/renderers/webgl/internal/RendererUtils.js +14 -0
  33. package/dist/src/core/renderers/webgl/internal/RendererUtils.js.map +1 -1
  34. package/dist/src/core/renderers/webgl/shaders/DefaultShader.js +47 -47
  35. package/dist/src/core/renderers/webgl/shaders/DefaultShaderBatched.js +61 -61
  36. package/dist/src/core/renderers/webgl/shaders/DynamicShader.js +93 -93
  37. package/dist/src/core/renderers/webgl/shaders/RoundedRectangle.js +63 -63
  38. package/dist/src/core/renderers/webgl/shaders/SdfShader.js +49 -49
  39. package/dist/src/core/renderers/webgl/shaders/effects/BorderBottomEffect.js +15 -15
  40. package/dist/src/core/renderers/webgl/shaders/effects/BorderEffect.js +5 -5
  41. package/dist/src/core/renderers/webgl/shaders/effects/BorderLeftEffect.js +15 -15
  42. package/dist/src/core/renderers/webgl/shaders/effects/BorderRightEffect.js +15 -15
  43. package/dist/src/core/renderers/webgl/shaders/effects/BorderTopEffect.js +15 -15
  44. package/dist/src/core/renderers/webgl/shaders/effects/FadeOutEffect.js +42 -42
  45. package/dist/src/core/renderers/webgl/shaders/effects/GlitchEffect.js +44 -44
  46. package/dist/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.js +3 -3
  47. package/dist/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.js +31 -31
  48. package/dist/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.js +13 -13
  49. package/dist/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.js +37 -37
  50. package/dist/src/core/renderers/webgl/shaders/effects/RadiusEffect.js +19 -19
  51. package/dist/src/core/scene/Scene.d.ts +59 -0
  52. package/dist/src/core/scene/Scene.js +106 -0
  53. package/dist/src/core/scene/Scene.js.map +1 -0
  54. package/dist/src/core/text-rendering/TrFontManager.js +30 -25
  55. package/dist/src/core/text-rendering/TrFontManager.js.map +1 -1
  56. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js +8 -2
  57. package/dist/src/core/text-rendering/renderers/CanvasTextRenderer.js.map +1 -1
  58. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js +8 -2
  59. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.js.map +1 -1
  60. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.d.ts +8 -0
  61. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js +29 -0
  62. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/findNearestMultiple.js.map +1 -0
  63. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.d.ts +19 -0
  64. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js +84 -0
  65. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/SdfBufferHelper.js.map +1 -0
  66. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.d.ts +8 -0
  67. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js +40 -0
  68. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutLine.js.map +1 -0
  69. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.d.ts +2 -0
  70. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js +41 -0
  71. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/layoutText2.js.map +1 -0
  72. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.d.ts +1 -0
  73. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js +4 -0
  74. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2/utils.js.map +1 -0
  75. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.d.ts +1 -0
  76. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js +2 -0
  77. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText2.js.map +1 -0
  78. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.d.ts +20 -0
  79. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.js +55 -0
  80. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/makeRenderWindow.js.map +1 -0
  81. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.d.ts +9 -0
  82. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js +32 -0
  83. package/dist/src/core/text-rendering/renderers/SdfTextRenderer/internal/roundUpToMultiple.js.map +1 -0
  84. package/dist/src/core/text-rendering/renderers/TextRenderer.d.ts +12 -0
  85. package/dist/src/core/text-rendering/renderers/TextRenderer.js.map +1 -1
  86. package/dist/src/core/textures/ImageTexture.js +16 -2
  87. package/dist/src/core/textures/ImageTexture.js.map +1 -1
  88. package/dist/src/core/textures/Texture.d.ts +1 -1
  89. package/dist/src/core/textures/Texture.js.map +1 -1
  90. package/dist/src/core/utils.d.ts +1 -1
  91. package/dist/src/main-api/RendererMain.d.ts +6 -0
  92. package/dist/src/main-api/RendererMain.js +1 -0
  93. package/dist/src/main-api/RendererMain.js.map +1 -1
  94. package/dist/src/render-drivers/main/MainCoreDriver.js +1 -0
  95. package/dist/src/render-drivers/main/MainCoreDriver.js.map +1 -1
  96. package/dist/src/render-drivers/main/MainOnlyNode.d.ts +4 -0
  97. package/dist/src/render-drivers/main/MainOnlyNode.js +22 -0
  98. package/dist/src/render-drivers/main/MainOnlyNode.js.map +1 -1
  99. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js +1 -0
  100. package/dist/src/render-drivers/threadx/ThreadXCoreDriver.js.map +1 -1
  101. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.d.ts +1 -0
  102. package/dist/src/render-drivers/threadx/ThreadXRendererMessage.js.map +1 -1
  103. package/dist/src/render-drivers/threadx/worker/renderer.js +1 -0
  104. package/dist/src/render-drivers/threadx/worker/renderer.js.map +1 -1
  105. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  106. package/exports/core-api.ts +102 -102
  107. package/exports/main-api.ts +60 -60
  108. package/exports/utils.ts +41 -41
  109. package/package.json +1 -1
  110. package/scripts/please-use-pnpm.js +13 -13
  111. package/src/common/CommonTypes.ts +125 -113
  112. package/src/common/EventEmitter.ts +77 -77
  113. package/src/common/IAnimationController.ts +29 -29
  114. package/src/core/CoreExtension.ts +32 -32
  115. package/src/core/CoreNode.ts +1114 -955
  116. package/src/core/CoreShaderManager.ts +243 -243
  117. package/src/core/CoreTextNode.ts +399 -391
  118. package/src/core/CoreTextureManager.ts +337 -326
  119. package/src/core/Stage.ts +365 -354
  120. package/src/core/animations/AnimationManager.ts +38 -38
  121. package/src/core/animations/CoreAnimation.ts +181 -181
  122. package/src/core/animations/CoreAnimationController.ts +148 -148
  123. package/src/core/lib/ContextSpy.ts +41 -41
  124. package/src/core/lib/ImageWorker.ts +149 -135
  125. package/src/core/lib/Matrix3d.ts +290 -290
  126. package/src/core/lib/RenderCoords.ts +86 -0
  127. package/src/core/lib/WebGlContextWrapper.ts +992 -992
  128. package/src/core/lib/textureCompression.ts +152 -152
  129. package/src/core/lib/utils.ts +250 -241
  130. package/src/core/platform.ts +46 -46
  131. package/src/core/renderers/CoreContextTexture.ts +30 -30
  132. package/src/core/renderers/CoreRenderOp.ts +22 -22
  133. package/src/core/renderers/CoreRenderer.ts +63 -63
  134. package/src/core/renderers/CoreShader.ts +41 -41
  135. package/src/core/renderers/webgl/WebGlCoreCtxSubTexture.ts +37 -37
  136. package/src/core/renderers/webgl/WebGlCoreCtxTexture.ts +233 -230
  137. package/src/core/renderers/webgl/WebGlCoreRenderOp.ts +107 -107
  138. package/src/core/renderers/webgl/WebGlCoreRenderer.ts +520 -520
  139. package/src/core/renderers/webgl/WebGlCoreShader.ts +337 -337
  140. package/src/core/renderers/webgl/internal/BufferCollection.ts +54 -54
  141. package/src/core/renderers/webgl/internal/RendererUtils.ts +148 -131
  142. package/src/core/renderers/webgl/internal/ShaderUtils.ts +136 -136
  143. package/src/core/renderers/webgl/internal/WebGlUtils.ts +35 -35
  144. package/src/core/renderers/webgl/shaders/DefaultShader.ts +95 -95
  145. package/src/core/renderers/webgl/shaders/DefaultShaderBatched.ts +132 -132
  146. package/src/core/renderers/webgl/shaders/DynamicShader.ts +474 -474
  147. package/src/core/renderers/webgl/shaders/RoundedRectangle.ts +161 -161
  148. package/src/core/renderers/webgl/shaders/SdfShader.ts +174 -174
  149. package/src/core/renderers/webgl/shaders/effects/BorderBottomEffect.ts +101 -101
  150. package/src/core/renderers/webgl/shaders/effects/BorderEffect.ts +86 -86
  151. package/src/core/renderers/webgl/shaders/effects/BorderLeftEffect.ts +101 -101
  152. package/src/core/renderers/webgl/shaders/effects/BorderRightEffect.ts +101 -101
  153. package/src/core/renderers/webgl/shaders/effects/BorderTopEffect.ts +101 -101
  154. package/src/core/renderers/webgl/shaders/effects/EffectUtils.ts +33 -33
  155. package/src/core/renderers/webgl/shaders/effects/FadeOutEffect.ts +135 -135
  156. package/src/core/renderers/webgl/shaders/effects/GlitchEffect.ts +145 -145
  157. package/src/core/renderers/webgl/shaders/effects/GrayscaleEffect.ts +67 -67
  158. package/src/core/renderers/webgl/shaders/effects/LinearGradientEffect.ts +176 -176
  159. package/src/core/renderers/webgl/shaders/effects/RadialGradientEffect.ts +159 -159
  160. package/src/core/renderers/webgl/shaders/effects/RadialProgressEffect.ts +186 -186
  161. package/src/core/renderers/webgl/shaders/effects/RadiusEffect.ts +121 -121
  162. package/src/core/renderers/webgl/shaders/effects/ShaderEffect.ts +114 -114
  163. package/src/core/text-rendering/TextTextureRendererUtils.ts +189 -189
  164. package/src/core/text-rendering/TrFontManager.ts +170 -166
  165. package/src/core/text-rendering/font-face-types/SdfTrFontFace/SdfTrFontFace.ts +141 -141
  166. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/FontShaper.ts +139 -139
  167. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.test.ts +173 -173
  168. package/src/core/text-rendering/font-face-types/SdfTrFontFace/internal/SdfFontShaper.ts +169 -169
  169. package/src/core/text-rendering/font-face-types/TrFontFace.ts +105 -105
  170. package/src/core/text-rendering/font-face-types/WebTrFontFace.ts +77 -77
  171. package/src/core/text-rendering/renderers/CanvasTextRenderer.ts +757 -751
  172. package/src/core/text-rendering/renderers/LightningTextTextureRenderer.ts +741 -741
  173. package/src/core/text-rendering/renderers/SdfTextRenderer/SdfTextRenderer.ts +784 -778
  174. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.test.ts +48 -48
  175. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/PeekableGenerator.ts +66 -66
  176. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/SpecialCodepoints.ts +52 -52
  177. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/constants.ts +32 -32
  178. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getStartConditions.ts +84 -84
  179. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.test.ts +133 -133
  180. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/getUnicodeCodepoints.ts +38 -38
  181. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/layoutText.ts +393 -393
  182. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.test.ts +49 -49
  183. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/measureText.ts +51 -51
  184. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.test.ts +205 -205
  185. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/setRenderWindow.ts +93 -93
  186. package/src/core/text-rendering/renderers/SdfTextRenderer/internal/util.ts +40 -40
  187. package/src/core/text-rendering/renderers/TextRenderer.ts +516 -504
  188. package/src/core/textures/ColorTexture.ts +86 -86
  189. package/src/core/textures/ImageTexture.ts +154 -140
  190. package/src/core/textures/NoiseTexture.ts +96 -96
  191. package/src/core/textures/SubTexture.ts +143 -143
  192. package/src/core/textures/Texture.ts +224 -218
  193. package/src/core/utils.ts +224 -224
  194. package/src/env.d.ts +7 -7
  195. package/src/main-api/ICoreDriver.ts +66 -66
  196. package/src/main-api/INode.ts +499 -499
  197. package/src/main-api/Inspector.ts +439 -439
  198. package/src/main-api/RendererMain.ts +659 -652
  199. package/src/main-api/texture-usage-trackers/FinalizationRegistryTextureUsageTracker.ts +45 -45
  200. package/src/main-api/texture-usage-trackers/ManualCountTextureUsageTracker.ts +154 -154
  201. package/src/main-api/texture-usage-trackers/TextureUsageTracker.ts +54 -54
  202. package/src/render-drivers/main/MainCoreDriver.ts +149 -148
  203. package/src/render-drivers/main/MainOnlyNode.ts +494 -466
  204. package/src/render-drivers/main/MainOnlyTextNode.ts +261 -261
  205. package/src/render-drivers/threadx/NodeStruct.ts +300 -300
  206. package/src/render-drivers/threadx/SharedNode.ts +97 -97
  207. package/src/render-drivers/threadx/TextNodeStruct.ts +211 -211
  208. package/src/render-drivers/threadx/ThreadXCoreDriver.ts +286 -285
  209. package/src/render-drivers/threadx/ThreadXMainAnimationController.ts +99 -99
  210. package/src/render-drivers/threadx/ThreadXMainNode.ts +192 -192
  211. package/src/render-drivers/threadx/ThreadXMainTextNode.ts +85 -85
  212. package/src/render-drivers/threadx/ThreadXRendererMessage.ts +111 -110
  213. package/src/render-drivers/threadx/worker/ThreadXRendererNode.ts +238 -238
  214. package/src/render-drivers/threadx/worker/ThreadXRendererTextNode.ts +149 -149
  215. package/src/render-drivers/threadx/worker/renderer.ts +152 -151
  216. package/src/render-drivers/utils.ts +97 -97
  217. package/src/utils.ts +207 -207
  218. package/COPYING +0 -1
@@ -1,439 +1,439 @@
1
- import type {
2
- INode,
3
- INodeAnimatableProps,
4
- INodeWritableProps,
5
- ITextNode,
6
- ITextNodeWritableProps,
7
- } from './INode.js';
8
- import type { ICoreDriver } from './ICoreDriver.js';
9
- import { type RendererMainSettings } from './RendererMain.js';
10
- import type { AnimationSettings } from '../core/animations/CoreAnimation.js';
11
- import type { IAnimationController } from '../common/IAnimationController.js';
12
-
13
- /**
14
- * Inspector
15
- *
16
- * The inspector is a tool that allows you to inspect the state of the renderer
17
- * and the nodes that are being rendered. It is a tool that is used for debugging
18
- * and development purposes.
19
- *
20
- * The inspector will generate a DOM tree that mirrors the state of the renderer
21
- */
22
-
23
- /**
24
- * stylePropertyMap is a map of renderer properties that are mapped to CSS properties
25
- *
26
- * It can either return a string or an object with a prop and value property. Once a
27
- * property is found in the map, the value is set on the style of the div element.
28
- * Erik H made me do it.
29
- */
30
- interface StyleResponse {
31
- prop: string;
32
- value: string;
33
- }
34
- const stylePropertyMap: {
35
- [key: string]: (
36
- value: string | number | boolean,
37
- ) => string | StyleResponse | null;
38
- } = {
39
- alpha: (v) => {
40
- if (v === 1) {
41
- return null;
42
- }
43
-
44
- return { prop: 'opacity', value: `${v}` };
45
- },
46
- x: (x) => {
47
- return { prop: 'left', value: `${x}px` };
48
- },
49
- y: (y) => {
50
- return { prop: 'top', value: `${y}px` };
51
- },
52
- width: (w) => {
53
- if (w === 0) {
54
- return null;
55
- }
56
-
57
- return { prop: 'width', value: `${w}px` };
58
- },
59
- height: (h) => {
60
- if (h === 0) {
61
- return null;
62
- }
63
-
64
- return { prop: 'height', value: `${h}px` };
65
- },
66
- zIndex: () => 'zIndex',
67
- fontFamily: () => 'font-family',
68
- fontSize: () => 'font-size',
69
- fontStyle: () => 'font-style',
70
- fontWeight: () => 'font-weight',
71
- fontStretch: () => 'font-stretch',
72
- lineHeight: () => 'line-height',
73
- letterSpacing: () => 'letter-spacing',
74
- textAlign: () => 'text-align',
75
- overflowSuffix: () => 'overflow-suffix',
76
- maxLines: () => 'max-lines',
77
- contain: () => 'contain',
78
- verticalAlign: () => 'vertical-align',
79
- clipping: (v) => {
80
- if (v === false) {
81
- return null;
82
- }
83
-
84
- return { prop: 'overflow', value: v ? 'hidden' : 'visible' };
85
- },
86
- rotation: (v) => {
87
- if (v === 0) {
88
- return null;
89
- }
90
-
91
- return { prop: 'transform', value: `rotate(${v}rad)` };
92
- },
93
- scale: (v) => {
94
- if (v === 1) {
95
- return null;
96
- }
97
-
98
- return { prop: 'transform', value: `scale(${v})` };
99
- },
100
- scaleX: (v) => {
101
- if (v === 1) {
102
- return null;
103
- }
104
-
105
- return { prop: 'transform', value: `scaleX(${v})` };
106
- },
107
- scaleY: (v) => {
108
- if (v === 1) {
109
- return null;
110
- }
111
-
112
- return { prop: 'transform', value: `scaleY(${v})` };
113
- },
114
- color: (v) => {
115
- if (v === 0) {
116
- return null;
117
- }
118
-
119
- return { prop: 'color', value: convertColorToRgba(v as number) };
120
- },
121
- };
122
-
123
- const convertColorToRgba = (color: number) => {
124
- const a = (color & 0xff) / 255;
125
- const b = (color >> 8) & 0xff;
126
- const g = (color >> 16) & 0xff;
127
- const r = (color >> 24) & 0xff;
128
- return `rgba(${r},${g},${b},${a})`;
129
- };
130
-
131
- const domPropertyMap: { [key: string]: string } = {
132
- id: 'id',
133
- };
134
-
135
- const gradientColorPropertyMap = [
136
- 'colorTop',
137
- 'colorBottom',
138
- 'colorLeft',
139
- 'colorRight',
140
- 'colorTl',
141
- 'colorTr',
142
- 'colorBl',
143
- 'colorBr',
144
- ];
145
-
146
- export class Inspector {
147
- private root: HTMLElement | null = null;
148
- private canvas: HTMLCanvasElement | null = null;
149
- private height = 1080;
150
- private width = 1920;
151
- private scaleX = 1;
152
- private scaleY = 1;
153
-
154
- constructor(canvas: HTMLCanvasElement, settings: RendererMainSettings) {
155
- if (import.meta.env.PROD) return;
156
-
157
- if (!settings) {
158
- throw new Error('settings is required');
159
- }
160
-
161
- // calc dimensions based on the devicePixelRatio
162
- this.height = Math.ceil(
163
- settings.appHeight ?? 1080 / (settings.deviceLogicalPixelRatio ?? 1),
164
- );
165
-
166
- this.width = Math.ceil(
167
- settings.appWidth ?? 1900 / (settings.deviceLogicalPixelRatio ?? 1),
168
- );
169
-
170
- this.scaleX = settings.deviceLogicalPixelRatio ?? 1;
171
- this.scaleY = settings.deviceLogicalPixelRatio ?? 1;
172
-
173
- this.canvas = canvas;
174
- this.root = document.createElement('div');
175
- this.setRootPosition();
176
- document.body.appendChild(this.root);
177
-
178
- //listen for changes on canvas
179
- const mutationObserver = new MutationObserver(
180
- this.setRootPosition.bind(this),
181
- );
182
- mutationObserver.observe(canvas, {
183
- attributes: true,
184
- childList: false,
185
- subtree: false,
186
- });
187
-
188
- // Create a ResizeObserver to watch for changes in the element's size
189
- const resizeObserver = new ResizeObserver(this.setRootPosition.bind(this));
190
- resizeObserver.observe(canvas);
191
-
192
- //listen for changes on window
193
- window.addEventListener('resize', this.setRootPosition.bind(this));
194
-
195
- console.warn('Inspector is enabled, this will impact performance');
196
- }
197
-
198
- setRootPosition() {
199
- if (this.root === null || this.canvas === null) {
200
- return;
201
- }
202
-
203
- // get the world position of the canvas object, so we can match the inspector to it
204
- const rect = this.canvas.getBoundingClientRect();
205
- const top = document.documentElement.scrollTop + rect.top;
206
- const left = document.documentElement.scrollLeft + rect.left;
207
-
208
- this.root.id = 'root';
209
- this.root.style.left = `${left}px`;
210
- this.root.style.top = `${top}px`;
211
- this.root.style.width = `${this.width}px`;
212
- this.root.style.height = `${this.height}px`;
213
- this.root.style.position = 'absolute';
214
- this.root.style.transformOrigin = '0 0 0';
215
- this.root.style.transform = `scale(${this.scaleX}, ${this.scaleY})`;
216
- this.root.style.overflow = 'hidden';
217
- this.root.style.zIndex = '65534';
218
- }
219
-
220
- createDiv(
221
- node: INode | ITextNode,
222
- properties: INodeWritableProps | ITextNodeWritableProps,
223
- ): HTMLElement {
224
- const div = document.createElement('div');
225
- div.style.position = 'absolute';
226
- div.id = node.id.toString();
227
-
228
- // set initial properties
229
- for (const key in properties) {
230
- this.updateNodeProperty(
231
- div,
232
- // really typescript? really?
233
- key as keyof (INodeWritableProps & ITextNodeWritableProps),
234
- (properties as INodeWritableProps & ITextNodeWritableProps)[
235
- key as keyof (INodeWritableProps & ITextNodeWritableProps)
236
- ],
237
- );
238
- }
239
-
240
- return div;
241
- }
242
-
243
- createNode(driver: ICoreDriver, properties: INodeWritableProps): INode {
244
- const node = driver.createNode(properties);
245
- const div = this.createDiv(node, properties);
246
-
247
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
248
- (div as any).node = node;
249
-
250
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
251
- (node as any).div = div;
252
-
253
- return this.createProxy(node, div);
254
- }
255
-
256
- createTextNode(
257
- driver: ICoreDriver,
258
- properties: ITextNodeWritableProps,
259
- ): ITextNode {
260
- const node = driver.createTextNode(properties);
261
- const div = this.createDiv(node, properties);
262
- return this.createProxy(node, div) as ITextNode;
263
- }
264
-
265
- createProxy(node: INode | ITextNode, div: HTMLElement): INode | ITextNode {
266
- return new Proxy(node, {
267
- set: (target, property: keyof INodeWritableProps, value) => {
268
- this.updateNodeProperty(div, property, value);
269
- return Reflect.set(target, property, value);
270
- },
271
- get: (target, property: keyof INode, receiver: any): any => {
272
- if (property === 'destroy') {
273
- this.destroyNode(target);
274
- }
275
-
276
- if (property === 'animate') {
277
- return (props: INodeAnimatableProps, settings: AnimationSettings) => {
278
- const anim = target.animate(props, settings);
279
-
280
- // Trap the animate start function so we can update the inspector accordingly
281
- return new Proxy(anim, {
282
- get: (target, property: keyof IAnimationController, receiver) => {
283
- if (property === 'start') {
284
- this.animateNode(div, node, props, settings);
285
- }
286
-
287
- return Reflect.get(target, property, receiver);
288
- },
289
- });
290
- };
291
- }
292
-
293
- return Reflect.get(target, property, receiver);
294
- },
295
- });
296
- }
297
-
298
- destroyNode(node: INode | ITextNode) {
299
- const div = document.getElementById(node.id.toString());
300
- div?.remove();
301
- }
302
-
303
- updateNodeProperty(
304
- div: HTMLElement,
305
- property: keyof INodeWritableProps | keyof ITextNodeWritableProps,
306
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
307
- value: any,
308
- ) {
309
- if (this.root === null || value === undefined || value === null) {
310
- return;
311
- }
312
-
313
- /**
314
- * Special case for parent property
315
- */
316
- if (property === 'parent') {
317
- const parentId: number = (value as INode).id;
318
-
319
- // only way to detect if the parent is the root node
320
- // if you are reading this and have a better way, please let me know
321
- if (parentId === 1) {
322
- this.root.appendChild(div);
323
- return;
324
- }
325
-
326
- const parent = document.getElementById(parentId.toString());
327
- parent?.appendChild(div);
328
- return;
329
- }
330
-
331
- // special case for text
332
- if (property === 'text') {
333
- div.innerHTML = String(value);
334
-
335
- // hide text because we can't render SDF fonts
336
- // it would look weird and obstruct the WebGL rendering
337
- div.style.visibility = 'hidden';
338
- return;
339
- }
340
-
341
- // special case for images
342
- // we're not setting any CSS properties to avoid images getting loaded twice
343
- // as the renderer will handle the loading of the image. Setting it to `data-src`
344
- if (property === 'src' && value) {
345
- div.setAttribute(`data-src`, String(value));
346
- return;
347
- }
348
-
349
- // special case for color gradients (normal colors are handled by the stylePropertyMap)
350
- // FIXME the renderer seems to return the same number for all colors
351
- // if (gradientColorPropertyMap.includes(property as string)) {
352
- // const color = convertColorToRgba(value as number);
353
- // div.setAttribute(`data-${property}`, color);
354
- // return;
355
- // }
356
-
357
- // CSS mappable attribute
358
- if (stylePropertyMap[property]) {
359
- const mappedStyleResponse = stylePropertyMap[property]?.(value);
360
-
361
- if (mappedStyleResponse === null) {
362
- return;
363
- }
364
-
365
- if (typeof mappedStyleResponse === 'string') {
366
- div.style.setProperty(mappedStyleResponse, String(value));
367
- return;
368
- }
369
-
370
- if (typeof mappedStyleResponse === 'object') {
371
- div.style.setProperty(
372
- mappedStyleResponse.prop,
373
- mappedStyleResponse.value,
374
- );
375
- }
376
-
377
- return;
378
- }
379
-
380
- // DOM properties
381
- if (domPropertyMap[property]) {
382
- div.setAttribute(String(stylePropertyMap[property]), String(value));
383
- return;
384
- }
385
-
386
- // custom data properties
387
- if (property === 'data') {
388
- for (const key in value) {
389
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
390
- div.setAttribute(`data-${key}`, String(value[key]));
391
- }
392
- return;
393
- }
394
- }
395
-
396
- // simple animation handler
397
- animateNode(
398
- div: HTMLElement,
399
- node: INode,
400
- props: INodeAnimatableProps,
401
- settings: AnimationSettings,
402
- ) {
403
- const {
404
- duration = 1000,
405
- delay = 0,
406
- // easing = 'linear',
407
- // repeat = 0,
408
- // loop = false,
409
- // stopMethod = false,
410
- } = settings;
411
-
412
- const {
413
- x,
414
- y,
415
- width,
416
- height,
417
- alpha = 1,
418
- rotation = 0,
419
- scale = 1,
420
- color,
421
- } = props;
422
-
423
- // ignoring loops and repeats for now, as that might be a bit too much for the inspector
424
- function animate() {
425
- setTimeout(() => {
426
- div.style.top = `${y}px`;
427
- div.style.left = `${x}px`;
428
- div.style.width = `${width}px`;
429
- div.style.height = `${height}px`;
430
- div.style.opacity = `${alpha}`;
431
- div.style.rotate = `${rotation}rad`;
432
- div.style.scale = `${scale}`;
433
- div.style.color = convertColorToRgba(color);
434
- }, duration);
435
- }
436
-
437
- setTimeout(animate, delay);
438
- }
439
- }
1
+ import type {
2
+ INode,
3
+ INodeAnimatableProps,
4
+ INodeWritableProps,
5
+ ITextNode,
6
+ ITextNodeWritableProps,
7
+ } from './INode.js';
8
+ import type { ICoreDriver } from './ICoreDriver.js';
9
+ import { type RendererMainSettings } from './RendererMain.js';
10
+ import type { AnimationSettings } from '../core/animations/CoreAnimation.js';
11
+ import type { IAnimationController } from '../common/IAnimationController.js';
12
+
13
+ /**
14
+ * Inspector
15
+ *
16
+ * The inspector is a tool that allows you to inspect the state of the renderer
17
+ * and the nodes that are being rendered. It is a tool that is used for debugging
18
+ * and development purposes.
19
+ *
20
+ * The inspector will generate a DOM tree that mirrors the state of the renderer
21
+ */
22
+
23
+ /**
24
+ * stylePropertyMap is a map of renderer properties that are mapped to CSS properties
25
+ *
26
+ * It can either return a string or an object with a prop and value property. Once a
27
+ * property is found in the map, the value is set on the style of the div element.
28
+ * Erik H made me do it.
29
+ */
30
+ interface StyleResponse {
31
+ prop: string;
32
+ value: string;
33
+ }
34
+ const stylePropertyMap: {
35
+ [key: string]: (
36
+ value: string | number | boolean,
37
+ ) => string | StyleResponse | null;
38
+ } = {
39
+ alpha: (v) => {
40
+ if (v === 1) {
41
+ return null;
42
+ }
43
+
44
+ return { prop: 'opacity', value: `${v}` };
45
+ },
46
+ x: (x) => {
47
+ return { prop: 'left', value: `${x}px` };
48
+ },
49
+ y: (y) => {
50
+ return { prop: 'top', value: `${y}px` };
51
+ },
52
+ width: (w) => {
53
+ if (w === 0) {
54
+ return null;
55
+ }
56
+
57
+ return { prop: 'width', value: `${w}px` };
58
+ },
59
+ height: (h) => {
60
+ if (h === 0) {
61
+ return null;
62
+ }
63
+
64
+ return { prop: 'height', value: `${h}px` };
65
+ },
66
+ zIndex: () => 'zIndex',
67
+ fontFamily: () => 'font-family',
68
+ fontSize: () => 'font-size',
69
+ fontStyle: () => 'font-style',
70
+ fontWeight: () => 'font-weight',
71
+ fontStretch: () => 'font-stretch',
72
+ lineHeight: () => 'line-height',
73
+ letterSpacing: () => 'letter-spacing',
74
+ textAlign: () => 'text-align',
75
+ overflowSuffix: () => 'overflow-suffix',
76
+ maxLines: () => 'max-lines',
77
+ contain: () => 'contain',
78
+ verticalAlign: () => 'vertical-align',
79
+ clipping: (v) => {
80
+ if (v === false) {
81
+ return null;
82
+ }
83
+
84
+ return { prop: 'overflow', value: v ? 'hidden' : 'visible' };
85
+ },
86
+ rotation: (v) => {
87
+ if (v === 0) {
88
+ return null;
89
+ }
90
+
91
+ return { prop: 'transform', value: `rotate(${v}rad)` };
92
+ },
93
+ scale: (v) => {
94
+ if (v === 1) {
95
+ return null;
96
+ }
97
+
98
+ return { prop: 'transform', value: `scale(${v})` };
99
+ },
100
+ scaleX: (v) => {
101
+ if (v === 1) {
102
+ return null;
103
+ }
104
+
105
+ return { prop: 'transform', value: `scaleX(${v})` };
106
+ },
107
+ scaleY: (v) => {
108
+ if (v === 1) {
109
+ return null;
110
+ }
111
+
112
+ return { prop: 'transform', value: `scaleY(${v})` };
113
+ },
114
+ color: (v) => {
115
+ if (v === 0) {
116
+ return null;
117
+ }
118
+
119
+ return { prop: 'color', value: convertColorToRgba(v as number) };
120
+ },
121
+ };
122
+
123
+ const convertColorToRgba = (color: number) => {
124
+ const a = (color & 0xff) / 255;
125
+ const b = (color >> 8) & 0xff;
126
+ const g = (color >> 16) & 0xff;
127
+ const r = (color >> 24) & 0xff;
128
+ return `rgba(${r},${g},${b},${a})`;
129
+ };
130
+
131
+ const domPropertyMap: { [key: string]: string } = {
132
+ id: 'id',
133
+ };
134
+
135
+ const gradientColorPropertyMap = [
136
+ 'colorTop',
137
+ 'colorBottom',
138
+ 'colorLeft',
139
+ 'colorRight',
140
+ 'colorTl',
141
+ 'colorTr',
142
+ 'colorBl',
143
+ 'colorBr',
144
+ ];
145
+
146
+ export class Inspector {
147
+ private root: HTMLElement | null = null;
148
+ private canvas: HTMLCanvasElement | null = null;
149
+ private height = 1080;
150
+ private width = 1920;
151
+ private scaleX = 1;
152
+ private scaleY = 1;
153
+
154
+ constructor(canvas: HTMLCanvasElement, settings: RendererMainSettings) {
155
+ if (import.meta.env.PROD) return;
156
+
157
+ if (!settings) {
158
+ throw new Error('settings is required');
159
+ }
160
+
161
+ // calc dimensions based on the devicePixelRatio
162
+ this.height = Math.ceil(
163
+ settings.appHeight ?? 1080 / (settings.deviceLogicalPixelRatio ?? 1),
164
+ );
165
+
166
+ this.width = Math.ceil(
167
+ settings.appWidth ?? 1900 / (settings.deviceLogicalPixelRatio ?? 1),
168
+ );
169
+
170
+ this.scaleX = settings.deviceLogicalPixelRatio ?? 1;
171
+ this.scaleY = settings.deviceLogicalPixelRatio ?? 1;
172
+
173
+ this.canvas = canvas;
174
+ this.root = document.createElement('div');
175
+ this.setRootPosition();
176
+ document.body.appendChild(this.root);
177
+
178
+ //listen for changes on canvas
179
+ const mutationObserver = new MutationObserver(
180
+ this.setRootPosition.bind(this),
181
+ );
182
+ mutationObserver.observe(canvas, {
183
+ attributes: true,
184
+ childList: false,
185
+ subtree: false,
186
+ });
187
+
188
+ // Create a ResizeObserver to watch for changes in the element's size
189
+ const resizeObserver = new ResizeObserver(this.setRootPosition.bind(this));
190
+ resizeObserver.observe(canvas);
191
+
192
+ //listen for changes on window
193
+ window.addEventListener('resize', this.setRootPosition.bind(this));
194
+
195
+ console.warn('Inspector is enabled, this will impact performance');
196
+ }
197
+
198
+ setRootPosition() {
199
+ if (this.root === null || this.canvas === null) {
200
+ return;
201
+ }
202
+
203
+ // get the world position of the canvas object, so we can match the inspector to it
204
+ const rect = this.canvas.getBoundingClientRect();
205
+ const top = document.documentElement.scrollTop + rect.top;
206
+ const left = document.documentElement.scrollLeft + rect.left;
207
+
208
+ this.root.id = 'root';
209
+ this.root.style.left = `${left}px`;
210
+ this.root.style.top = `${top}px`;
211
+ this.root.style.width = `${this.width}px`;
212
+ this.root.style.height = `${this.height}px`;
213
+ this.root.style.position = 'absolute';
214
+ this.root.style.transformOrigin = '0 0 0';
215
+ this.root.style.transform = `scale(${this.scaleX}, ${this.scaleY})`;
216
+ this.root.style.overflow = 'hidden';
217
+ this.root.style.zIndex = '65534';
218
+ }
219
+
220
+ createDiv(
221
+ node: INode | ITextNode,
222
+ properties: INodeWritableProps | ITextNodeWritableProps,
223
+ ): HTMLElement {
224
+ const div = document.createElement('div');
225
+ div.style.position = 'absolute';
226
+ div.id = node.id.toString();
227
+
228
+ // set initial properties
229
+ for (const key in properties) {
230
+ this.updateNodeProperty(
231
+ div,
232
+ // really typescript? really?
233
+ key as keyof (INodeWritableProps & ITextNodeWritableProps),
234
+ (properties as INodeWritableProps & ITextNodeWritableProps)[
235
+ key as keyof (INodeWritableProps & ITextNodeWritableProps)
236
+ ],
237
+ );
238
+ }
239
+
240
+ return div;
241
+ }
242
+
243
+ createNode(driver: ICoreDriver, properties: INodeWritableProps): INode {
244
+ const node = driver.createNode(properties);
245
+ const div = this.createDiv(node, properties);
246
+
247
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
248
+ (div as any).node = node;
249
+
250
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
251
+ (node as any).div = div;
252
+
253
+ return this.createProxy(node, div);
254
+ }
255
+
256
+ createTextNode(
257
+ driver: ICoreDriver,
258
+ properties: ITextNodeWritableProps,
259
+ ): ITextNode {
260
+ const node = driver.createTextNode(properties);
261
+ const div = this.createDiv(node, properties);
262
+ return this.createProxy(node, div) as ITextNode;
263
+ }
264
+
265
+ createProxy(node: INode | ITextNode, div: HTMLElement): INode | ITextNode {
266
+ return new Proxy(node, {
267
+ set: (target, property: keyof INodeWritableProps, value) => {
268
+ this.updateNodeProperty(div, property, value);
269
+ return Reflect.set(target, property, value);
270
+ },
271
+ get: (target, property: keyof INode, receiver: any): any => {
272
+ if (property === 'destroy') {
273
+ this.destroyNode(target);
274
+ }
275
+
276
+ if (property === 'animate') {
277
+ return (props: INodeAnimatableProps, settings: AnimationSettings) => {
278
+ const anim = target.animate(props, settings);
279
+
280
+ // Trap the animate start function so we can update the inspector accordingly
281
+ return new Proxy(anim, {
282
+ get: (target, property: keyof IAnimationController, receiver) => {
283
+ if (property === 'start') {
284
+ this.animateNode(div, node, props, settings);
285
+ }
286
+
287
+ return Reflect.get(target, property, receiver);
288
+ },
289
+ });
290
+ };
291
+ }
292
+
293
+ return Reflect.get(target, property, receiver);
294
+ },
295
+ });
296
+ }
297
+
298
+ destroyNode(node: INode | ITextNode) {
299
+ const div = document.getElementById(node.id.toString());
300
+ div?.remove();
301
+ }
302
+
303
+ updateNodeProperty(
304
+ div: HTMLElement,
305
+ property: keyof INodeWritableProps | keyof ITextNodeWritableProps,
306
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
307
+ value: any,
308
+ ) {
309
+ if (this.root === null || value === undefined || value === null) {
310
+ return;
311
+ }
312
+
313
+ /**
314
+ * Special case for parent property
315
+ */
316
+ if (property === 'parent') {
317
+ const parentId: number = (value as INode).id;
318
+
319
+ // only way to detect if the parent is the root node
320
+ // if you are reading this and have a better way, please let me know
321
+ if (parentId === 1) {
322
+ this.root.appendChild(div);
323
+ return;
324
+ }
325
+
326
+ const parent = document.getElementById(parentId.toString());
327
+ parent?.appendChild(div);
328
+ return;
329
+ }
330
+
331
+ // special case for text
332
+ if (property === 'text') {
333
+ div.innerHTML = String(value);
334
+
335
+ // hide text because we can't render SDF fonts
336
+ // it would look weird and obstruct the WebGL rendering
337
+ div.style.visibility = 'hidden';
338
+ return;
339
+ }
340
+
341
+ // special case for images
342
+ // we're not setting any CSS properties to avoid images getting loaded twice
343
+ // as the renderer will handle the loading of the image. Setting it to `data-src`
344
+ if (property === 'src' && value) {
345
+ div.setAttribute(`data-src`, String(value));
346
+ return;
347
+ }
348
+
349
+ // special case for color gradients (normal colors are handled by the stylePropertyMap)
350
+ // FIXME the renderer seems to return the same number for all colors
351
+ // if (gradientColorPropertyMap.includes(property as string)) {
352
+ // const color = convertColorToRgba(value as number);
353
+ // div.setAttribute(`data-${property}`, color);
354
+ // return;
355
+ // }
356
+
357
+ // CSS mappable attribute
358
+ if (stylePropertyMap[property]) {
359
+ const mappedStyleResponse = stylePropertyMap[property]?.(value);
360
+
361
+ if (mappedStyleResponse === null) {
362
+ return;
363
+ }
364
+
365
+ if (typeof mappedStyleResponse === 'string') {
366
+ div.style.setProperty(mappedStyleResponse, String(value));
367
+ return;
368
+ }
369
+
370
+ if (typeof mappedStyleResponse === 'object') {
371
+ div.style.setProperty(
372
+ mappedStyleResponse.prop,
373
+ mappedStyleResponse.value,
374
+ );
375
+ }
376
+
377
+ return;
378
+ }
379
+
380
+ // DOM properties
381
+ if (domPropertyMap[property]) {
382
+ div.setAttribute(String(stylePropertyMap[property]), String(value));
383
+ return;
384
+ }
385
+
386
+ // custom data properties
387
+ if (property === 'data') {
388
+ for (const key in value) {
389
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
390
+ div.setAttribute(`data-${key}`, String(value[key]));
391
+ }
392
+ return;
393
+ }
394
+ }
395
+
396
+ // simple animation handler
397
+ animateNode(
398
+ div: HTMLElement,
399
+ node: INode,
400
+ props: INodeAnimatableProps,
401
+ settings: AnimationSettings,
402
+ ) {
403
+ const {
404
+ duration = 1000,
405
+ delay = 0,
406
+ // easing = 'linear',
407
+ // repeat = 0,
408
+ // loop = false,
409
+ // stopMethod = false,
410
+ } = settings;
411
+
412
+ const {
413
+ x,
414
+ y,
415
+ width,
416
+ height,
417
+ alpha = 1,
418
+ rotation = 0,
419
+ scale = 1,
420
+ color,
421
+ } = props;
422
+
423
+ // ignoring loops and repeats for now, as that might be a bit too much for the inspector
424
+ function animate() {
425
+ setTimeout(() => {
426
+ div.style.top = `${y}px`;
427
+ div.style.left = `${x}px`;
428
+ div.style.width = `${width}px`;
429
+ div.style.height = `${height}px`;
430
+ div.style.opacity = `${alpha}`;
431
+ div.style.rotate = `${rotation}rad`;
432
+ div.style.scale = `${scale}`;
433
+ div.style.color = convertColorToRgba(color);
434
+ }, duration);
435
+ }
436
+
437
+ setTimeout(animate, delay);
438
+ }
439
+ }