@codexo/exojs 0.8.4 → 0.9.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 (317) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +26 -5
  3. package/dist/esm/animation/Tween.d.ts +20 -3
  4. package/dist/esm/animation/Tween.js +16 -8
  5. package/dist/esm/animation/Tween.js.map +1 -1
  6. package/dist/esm/animation/TweenManager.d.ts +16 -1
  7. package/dist/esm/animation/TweenManager.js +27 -2
  8. package/dist/esm/animation/TweenManager.js.map +1 -1
  9. package/dist/esm/audio/AudioAnalyser.d.ts +2 -0
  10. package/dist/esm/audio/AudioAnalyser.js +24 -9
  11. package/dist/esm/audio/AudioAnalyser.js.map +1 -1
  12. package/dist/esm/audio/AudioBus.d.ts +1 -0
  13. package/dist/esm/audio/AudioBus.js +8 -4
  14. package/dist/esm/audio/AudioBus.js.map +1 -1
  15. package/dist/esm/audio/AudioListener.d.ts +1 -0
  16. package/dist/esm/audio/AudioListener.js +7 -5
  17. package/dist/esm/audio/AudioListener.js.map +1 -1
  18. package/dist/esm/audio/AudioManager.d.ts +8 -2
  19. package/dist/esm/audio/AudioManager.js +14 -1
  20. package/dist/esm/audio/AudioManager.js.map +1 -1
  21. package/dist/esm/audio/BeatDetector.d.ts +2 -0
  22. package/dist/esm/audio/BeatDetector.js +27 -661
  23. package/dist/esm/audio/BeatDetector.js.map +1 -1
  24. package/dist/esm/audio/Music.d.ts +1 -0
  25. package/dist/esm/audio/Music.js +7 -3
  26. package/dist/esm/audio/Music.js.map +1 -1
  27. package/dist/esm/audio/OscillatorSound.d.ts +1 -0
  28. package/dist/esm/audio/OscillatorSound.js +7 -3
  29. package/dist/esm/audio/OscillatorSound.js.map +1 -1
  30. package/dist/esm/audio/Sound.d.ts +1 -0
  31. package/dist/esm/audio/Sound.js +7 -3
  32. package/dist/esm/audio/Sound.js.map +1 -1
  33. package/dist/esm/audio/audio-context.d.ts +2 -2
  34. package/dist/esm/audio/audio-context.js +4 -4
  35. package/dist/esm/audio/audio-context.js.map +1 -1
  36. package/dist/esm/audio/filters/ChorusFilter.d.ts +1 -0
  37. package/dist/esm/audio/filters/ChorusFilter.js +7 -3
  38. package/dist/esm/audio/filters/ChorusFilter.js.map +1 -1
  39. package/dist/esm/audio/filters/CompressorFilter.d.ts +1 -0
  40. package/dist/esm/audio/filters/CompressorFilter.js +7 -3
  41. package/dist/esm/audio/filters/CompressorFilter.js.map +1 -1
  42. package/dist/esm/audio/filters/DelayFilter.d.ts +1 -0
  43. package/dist/esm/audio/filters/DelayFilter.js +7 -3
  44. package/dist/esm/audio/filters/DelayFilter.js.map +1 -1
  45. package/dist/esm/audio/filters/EqualizerFilter.d.ts +1 -0
  46. package/dist/esm/audio/filters/EqualizerFilter.js +7 -3
  47. package/dist/esm/audio/filters/EqualizerFilter.js.map +1 -1
  48. package/dist/esm/audio/filters/GranularFilter.js +1 -86
  49. package/dist/esm/audio/filters/GranularFilter.js.map +1 -1
  50. package/dist/esm/audio/filters/HighpassFilter.d.ts +1 -0
  51. package/dist/esm/audio/filters/HighpassFilter.js +7 -3
  52. package/dist/esm/audio/filters/HighpassFilter.js.map +1 -1
  53. package/dist/esm/audio/filters/LowpassFilter.d.ts +1 -0
  54. package/dist/esm/audio/filters/LowpassFilter.js +7 -3
  55. package/dist/esm/audio/filters/LowpassFilter.js.map +1 -1
  56. package/dist/esm/audio/filters/PitchShiftFilter.js +1 -71
  57. package/dist/esm/audio/filters/PitchShiftFilter.js.map +1 -1
  58. package/dist/esm/audio/filters/ReverbFilter.d.ts +1 -0
  59. package/dist/esm/audio/filters/ReverbFilter.js +7 -3
  60. package/dist/esm/audio/filters/ReverbFilter.js.map +1 -1
  61. package/dist/esm/audio/filters/VocoderFilter.js +1 -89
  62. package/dist/esm/audio/filters/VocoderFilter.js.map +1 -1
  63. package/dist/esm/audio/filters/WorkletFilter.d.ts +2 -0
  64. package/dist/esm/audio/filters/WorkletFilter.js +10 -5
  65. package/dist/esm/audio/filters/WorkletFilter.js.map +1 -1
  66. package/dist/esm/audio/index.d.ts +15 -10
  67. package/dist/esm/audio/worklet/registerWorklet.d.ts +1 -1
  68. package/dist/esm/audio/worklet/registerWorklet.js +2 -2
  69. package/dist/esm/audio/worklet/registerWorklet.js.map +1 -1
  70. package/dist/esm/audio/worklets/beat-detector.worklet.d.ts +1 -0
  71. package/dist/esm/audio/worklets/beat-detector.worklet.js +647 -0
  72. package/dist/esm/audio/worklets/beat-detector.worklet.js.map +1 -0
  73. package/dist/esm/audio/worklets/granular.worklet.d.ts +1 -0
  74. package/dist/esm/audio/worklets/granular.worklet.js +89 -0
  75. package/dist/esm/audio/worklets/granular.worklet.js.map +1 -0
  76. package/dist/esm/audio/worklets/pitch-shift.worklet.d.ts +1 -0
  77. package/dist/esm/audio/worklets/pitch-shift.worklet.js +74 -0
  78. package/dist/esm/audio/worklets/pitch-shift.worklet.js.map +1 -0
  79. package/dist/esm/audio/worklets/vocoder.worklet.d.ts +1 -0
  80. package/dist/esm/audio/worklets/vocoder.worklet.js +92 -0
  81. package/dist/esm/audio/worklets/vocoder.worklet.js.map +1 -0
  82. package/dist/esm/core/Application.d.ts +62 -24
  83. package/dist/esm/core/Application.js +116 -40
  84. package/dist/esm/core/Application.js.map +1 -1
  85. package/dist/esm/core/Color.d.ts +0 -8
  86. package/dist/esm/core/Color.js +0 -24
  87. package/dist/esm/core/Color.js.map +1 -1
  88. package/dist/esm/core/Scene.d.ts +32 -72
  89. package/dist/esm/core/Scene.js +56 -36
  90. package/dist/esm/core/Scene.js.map +1 -1
  91. package/dist/esm/core/SceneManager.d.ts +11 -25
  92. package/dist/esm/core/SceneManager.js +37 -100
  93. package/dist/esm/core/SceneManager.js.map +1 -1
  94. package/dist/esm/core/SceneNode.d.ts +28 -14
  95. package/dist/esm/core/SceneNode.js +66 -33
  96. package/dist/esm/core/SceneNode.js.map +1 -1
  97. package/dist/esm/core/Signal.d.ts +24 -28
  98. package/dist/esm/core/Signal.js +64 -50
  99. package/dist/esm/core/Signal.js.map +1 -1
  100. package/dist/esm/core/Timer.d.ts +1 -0
  101. package/dist/esm/core/Timer.js +3 -0
  102. package/dist/esm/core/Timer.js.map +1 -1
  103. package/dist/esm/debug/BoundingBoxesLayer.js +1 -1
  104. package/dist/esm/debug/BoundingBoxesLayer.js.map +1 -1
  105. package/dist/esm/debug/HitTestLayer.js +1 -1
  106. package/dist/esm/debug/HitTestLayer.js.map +1 -1
  107. package/dist/esm/debug/PerformanceLayer.js +1 -2
  108. package/dist/esm/debug/PerformanceLayer.js.map +1 -1
  109. package/dist/esm/debug/PointerStackLayer.js +1 -2
  110. package/dist/esm/debug/PointerStackLayer.js.map +1 -1
  111. package/dist/esm/debug/RenderPassInspectorLayer.js +1 -2
  112. package/dist/esm/debug/RenderPassInspectorLayer.js.map +1 -1
  113. package/dist/esm/index.js +23 -7
  114. package/dist/esm/index.js.map +1 -1
  115. package/dist/esm/input/InputManager.d.ts +1 -0
  116. package/dist/esm/input/InputManager.js +30 -3
  117. package/dist/esm/input/InputManager.js.map +1 -1
  118. package/dist/esm/input/InteractionManager.d.ts +5 -2
  119. package/dist/esm/input/InteractionManager.js +29 -18
  120. package/dist/esm/input/InteractionManager.js.map +1 -1
  121. package/dist/esm/input/Pointer.js +3 -2
  122. package/dist/esm/input/Pointer.js.map +1 -1
  123. package/dist/esm/input/internal/interactionManagerRegistry.d.ts +9 -0
  124. package/dist/esm/input/internal/interactionManagerRegistry.js +10 -0
  125. package/dist/esm/input/internal/interactionManagerRegistry.js.map +1 -0
  126. package/dist/esm/math/AbstractVector.d.ts +1 -7
  127. package/dist/esm/math/AbstractVector.js +6 -20
  128. package/dist/esm/math/AbstractVector.js.map +1 -1
  129. package/dist/esm/math/Circle.js +0 -2
  130. package/dist/esm/math/Circle.js.map +1 -1
  131. package/dist/esm/math/Collision.d.ts +9 -3
  132. package/dist/esm/math/Ellipse.d.ts +2 -5
  133. package/dist/esm/math/Ellipse.js +10 -7
  134. package/dist/esm/math/Ellipse.js.map +1 -1
  135. package/dist/esm/math/ObservableVector.d.ts +1 -1
  136. package/dist/esm/math/ObservableVector.js +3 -3
  137. package/dist/esm/math/ObservableVector.js.map +1 -1
  138. package/dist/esm/math/Polygon.d.ts +0 -2
  139. package/dist/esm/math/Polygon.js +1 -9
  140. package/dist/esm/math/Polygon.js.map +1 -1
  141. package/dist/esm/math/Rectangle.js +0 -2
  142. package/dist/esm/math/Rectangle.js.map +1 -1
  143. package/dist/esm/math/collision-detection.d.ts +19 -4
  144. package/dist/esm/math/collision-detection.js +61 -4
  145. package/dist/esm/math/collision-detection.js.map +1 -1
  146. package/dist/esm/math/swept-collision.d.ts +16 -12
  147. package/dist/esm/math/swept-collision.js +109 -19
  148. package/dist/esm/math/swept-collision.js.map +1 -1
  149. package/dist/esm/particles/ParticleSystem.js +1 -1
  150. package/dist/esm/particles/ParticleSystem.js.map +1 -1
  151. package/dist/esm/particles/index.d.ts +1 -0
  152. package/dist/esm/rendering/CallbackRenderPass.d.ts +1 -0
  153. package/dist/esm/rendering/CallbackRenderPass.js +1 -0
  154. package/dist/esm/rendering/CallbackRenderPass.js.map +1 -1
  155. package/dist/esm/rendering/Container.d.ts +2 -1
  156. package/dist/esm/rendering/Container.js +17 -16
  157. package/dist/esm/rendering/Container.js.map +1 -1
  158. package/dist/esm/rendering/RenderBackend.d.ts +1 -0
  159. package/dist/esm/rendering/RenderNode.d.ts +1 -3
  160. package/dist/esm/rendering/RenderNode.js +12 -19
  161. package/dist/esm/rendering/RenderNode.js.map +1 -1
  162. package/dist/esm/rendering/RenderPass.d.ts +1 -0
  163. package/dist/esm/rendering/RenderStats.d.ts +9 -0
  164. package/dist/esm/rendering/RenderStats.js +2 -0
  165. package/dist/esm/rendering/RenderStats.js.map +1 -1
  166. package/dist/esm/rendering/RendererRegistry.d.ts +1 -0
  167. package/dist/esm/rendering/RendererRegistry.js +1 -0
  168. package/dist/esm/rendering/RendererRegistry.js.map +1 -1
  169. package/dist/esm/rendering/View.d.ts +23 -0
  170. package/dist/esm/rendering/View.js +42 -0
  171. package/dist/esm/rendering/View.js.map +1 -1
  172. package/dist/esm/rendering/index.d.ts +89 -59
  173. package/dist/esm/rendering/mesh/Mesh.js +1 -1
  174. package/dist/esm/rendering/mesh/Mesh.js.map +1 -1
  175. package/dist/esm/rendering/mesh/MeshShader.d.ts +1 -0
  176. package/dist/esm/rendering/mesh/MeshShader.js +1 -0
  177. package/dist/esm/rendering/mesh/MeshShader.js.map +1 -1
  178. package/dist/esm/rendering/shader/Shader.d.ts +1 -0
  179. package/dist/esm/rendering/shader/Shader.js +1 -0
  180. package/dist/esm/rendering/shader/Shader.js.map +1 -1
  181. package/dist/esm/rendering/shader/ShaderUniform.d.ts +1 -0
  182. package/dist/esm/rendering/shader/ShaderUniform.js +1 -0
  183. package/dist/esm/rendering/shader/ShaderUniform.js.map +1 -1
  184. package/dist/esm/rendering/sprite/Sprite.d.ts +3 -2
  185. package/dist/esm/rendering/sprite/Sprite.js +15 -13
  186. package/dist/esm/rendering/sprite/Sprite.js.map +1 -1
  187. package/dist/esm/rendering/text/AbstractText.d.ts +36 -0
  188. package/dist/esm/rendering/text/AbstractText.js +49 -0
  189. package/dist/esm/rendering/text/AbstractText.js.map +1 -0
  190. package/dist/esm/rendering/text/BitmapText.d.ts +97 -0
  191. package/dist/esm/rendering/text/BitmapText.js +220 -0
  192. package/dist/esm/rendering/text/BitmapText.js.map +1 -0
  193. package/dist/esm/rendering/text/BmFont.d.ts +50 -0
  194. package/dist/esm/rendering/text/BmFont.js +24 -0
  195. package/dist/esm/rendering/text/BmFont.js.map +1 -0
  196. package/dist/esm/rendering/text/GlyphAtlas.d.ts +104 -0
  197. package/dist/esm/rendering/text/GlyphAtlas.js +347 -0
  198. package/dist/esm/rendering/text/GlyphAtlas.js.map +1 -0
  199. package/dist/esm/rendering/text/GlyphAtlasPool.d.ts +40 -0
  200. package/dist/esm/rendering/text/GlyphAtlasPool.js +67 -0
  201. package/dist/esm/rendering/text/GlyphAtlasPool.js.map +1 -0
  202. package/dist/esm/rendering/text/GlyphSdf.d.ts +92 -0
  203. package/dist/esm/rendering/text/GlyphSdf.js +220 -0
  204. package/dist/esm/rendering/text/GlyphSdf.js.map +1 -0
  205. package/dist/esm/rendering/text/HTMLText.d.ts +107 -0
  206. package/dist/esm/rendering/text/HTMLText.js +284 -0
  207. package/dist/esm/rendering/text/HTMLText.js.map +1 -0
  208. package/dist/esm/rendering/text/LayoutOptions.d.ts +30 -0
  209. package/dist/esm/rendering/text/Text.d.ts +89 -20
  210. package/dist/esm/rendering/text/Text.js +176 -101
  211. package/dist/esm/rendering/text/Text.js.map +1 -1
  212. package/dist/esm/rendering/text/TextLayout.d.ts +20 -8
  213. package/dist/esm/rendering/text/TextLayout.js +234 -25
  214. package/dist/esm/rendering/text/TextLayout.js.map +1 -1
  215. package/dist/esm/rendering/text/TextStyle.d.ts +154 -87
  216. package/dist/esm/rendering/text/TextStyle.js +257 -203
  217. package/dist/esm/rendering/text/TextStyle.js.map +1 -1
  218. package/dist/esm/rendering/text/types.d.ts +73 -13
  219. package/dist/esm/rendering/texture/Texture.d.ts +1 -0
  220. package/dist/esm/rendering/texture/Texture.js +1 -0
  221. package/dist/esm/rendering/texture/Texture.js.map +1 -1
  222. package/dist/esm/rendering/types.d.ts +3 -1
  223. package/dist/esm/rendering/types.js +2 -0
  224. package/dist/esm/rendering/types.js.map +1 -1
  225. package/dist/esm/rendering/video/Video.d.ts +2 -1
  226. package/dist/esm/rendering/video/Video.js +9 -5
  227. package/dist/esm/rendering/video/Video.js.map +1 -1
  228. package/dist/esm/rendering/webgl2/WebGl2Backend.js +41 -5
  229. package/dist/esm/rendering/webgl2/WebGl2Backend.js.map +1 -1
  230. package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.js +4 -4
  231. package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.js.map +1 -1
  232. package/dist/esm/rendering/webgl2/WebGl2TextRenderer.d.ts +56 -0
  233. package/dist/esm/rendering/webgl2/WebGl2TextRenderer.js +482 -0
  234. package/dist/esm/rendering/webgl2/WebGl2TextRenderer.js.map +1 -0
  235. package/dist/esm/rendering/webgl2/glsl/text-color.frag.js +4 -0
  236. package/dist/esm/rendering/webgl2/glsl/text-color.frag.js.map +1 -0
  237. package/dist/esm/rendering/webgl2/glsl/text-msdf.frag.js +4 -0
  238. package/dist/esm/rendering/webgl2/glsl/text-msdf.frag.js.map +1 -0
  239. package/dist/esm/rendering/webgl2/glsl/text-sdf.frag.js +4 -0
  240. package/dist/esm/rendering/webgl2/glsl/text-sdf.frag.js.map +1 -0
  241. package/dist/esm/rendering/webgl2/glsl/text.vert.js +4 -0
  242. package/dist/esm/rendering/webgl2/glsl/text.vert.js.map +1 -0
  243. package/dist/esm/rendering/webgpu/WebGpuBackend.js +16 -8
  244. package/dist/esm/rendering/webgpu/WebGpuBackend.js.map +1 -1
  245. package/dist/esm/rendering/webgpu/WebGpuBlendState.js +26 -0
  246. package/dist/esm/rendering/webgpu/WebGpuBlendState.js.map +1 -1
  247. package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.d.ts +2 -2
  248. package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.js +23 -15
  249. package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.js.map +1 -1
  250. package/dist/esm/rendering/webgpu/WebGpuSpriteRenderer.js +9 -1
  251. package/dist/esm/rendering/webgpu/WebGpuSpriteRenderer.js.map +1 -1
  252. package/dist/esm/rendering/webgpu/WebGpuTextRenderer.d.ts +70 -0
  253. package/dist/esm/rendering/webgpu/WebGpuTextRenderer.js +773 -0
  254. package/dist/esm/rendering/webgpu/WebGpuTextRenderer.js.map +1 -0
  255. package/dist/esm/rendering/webgpu/compute/WebGpuComputePipeline.js +96 -0
  256. package/dist/esm/rendering/webgpu/compute/WebGpuComputePipeline.js.map +1 -0
  257. package/dist/esm/rendering/webgpu/compute/WebGpuStorageBuffer.js +68 -0
  258. package/dist/esm/rendering/webgpu/compute/WebGpuStorageBuffer.js.map +1 -0
  259. package/dist/esm/resources/Asset.d.ts +23 -0
  260. package/dist/esm/resources/Asset.js +23 -0
  261. package/dist/esm/resources/Asset.js.map +1 -0
  262. package/dist/esm/resources/AssetDefinitions.d.ts +137 -0
  263. package/dist/esm/resources/Assets.d.ts +35 -0
  264. package/dist/esm/resources/Assets.js +32 -0
  265. package/dist/esm/resources/Assets.js.map +1 -0
  266. package/dist/esm/resources/IndexedDbDatabase.js +17 -1
  267. package/dist/esm/resources/IndexedDbDatabase.js.map +1 -1
  268. package/dist/esm/resources/IndexedDbStore.js +17 -1
  269. package/dist/esm/resources/IndexedDbStore.js.map +1 -1
  270. package/dist/esm/resources/Loader.d.ts +244 -18
  271. package/dist/esm/resources/Loader.js +456 -50
  272. package/dist/esm/resources/Loader.js.map +1 -1
  273. package/dist/esm/resources/LoadingQueue.d.ts +28 -0
  274. package/dist/esm/resources/LoadingQueue.js +59 -0
  275. package/dist/esm/resources/LoadingQueue.js.map +1 -0
  276. package/dist/esm/resources/factories/BmFontFactory.d.ts +25 -0
  277. package/dist/esm/resources/factories/BmFontFactory.js +96 -0
  278. package/dist/esm/resources/factories/BmFontFactory.js.map +1 -0
  279. package/dist/esm/resources/factories/CsvFactory.d.ts +35 -0
  280. package/dist/esm/resources/factories/CsvFactory.js +87 -0
  281. package/dist/esm/resources/factories/CsvFactory.js.map +1 -0
  282. package/dist/esm/resources/factories/MusicFactory.d.ts +8 -2
  283. package/dist/esm/resources/factories/MusicFactory.js +25 -14
  284. package/dist/esm/resources/factories/MusicFactory.js.map +1 -1
  285. package/dist/esm/resources/factories/SoundFactory.d.ts +2 -2
  286. package/dist/esm/resources/factories/SoundFactory.js.map +1 -1
  287. package/dist/esm/resources/factories/SubtitleFactory.d.ts +28 -0
  288. package/dist/esm/resources/factories/SubtitleFactory.js +203 -0
  289. package/dist/esm/resources/factories/SubtitleFactory.js.map +1 -0
  290. package/dist/esm/resources/factories/SvgFactory.d.ts +18 -1
  291. package/dist/esm/resources/factories/SvgFactory.js +21 -2
  292. package/dist/esm/resources/factories/SvgFactory.js.map +1 -1
  293. package/dist/esm/resources/factories/VideoFactory.d.ts +8 -2
  294. package/dist/esm/resources/factories/VideoFactory.js +27 -20
  295. package/dist/esm/resources/factories/VideoFactory.js.map +1 -1
  296. package/dist/esm/resources/factories/XmlFactory.d.ts +24 -0
  297. package/dist/esm/resources/factories/XmlFactory.js +37 -0
  298. package/dist/esm/resources/factories/XmlFactory.js.map +1 -0
  299. package/dist/esm/resources/index.d.ts +8 -1
  300. package/dist/esm/resources/tokens.d.ts +49 -3
  301. package/dist/esm/resources/tokens.js +50 -4
  302. package/dist/esm/resources/tokens.js.map +1 -1
  303. package/dist/exo.esm.js +6635 -2550
  304. package/dist/exo.esm.js.map +1 -1
  305. package/package.json +16 -4
  306. package/dist/esm/input/interaction-hooks.d.ts +0 -34
  307. package/dist/esm/input/interaction-hooks.js +0 -35
  308. package/dist/esm/input/interaction-hooks.js.map +0 -1
  309. package/dist/esm/rendering/text/DynamicGlyphAtlas.d.ts +0 -33
  310. package/dist/esm/rendering/text/DynamicGlyphAtlas.js +0 -134
  311. package/dist/esm/rendering/text/DynamicGlyphAtlas.js.map +0 -1
  312. package/dist/esm/rendering/text/atlas-singleton.d.ts +0 -7
  313. package/dist/esm/rendering/text/atlas-singleton.js +0 -17
  314. package/dist/esm/rendering/text/atlas-singleton.js.map +0 -1
  315. package/dist/esm/resources/factories/VttFactory.d.ts +0 -24
  316. package/dist/esm/resources/factories/VttFactory.js +0 -158
  317. package/dist/esm/resources/factories/VttFactory.js.map +0 -1
@@ -1,41 +1,95 @@
1
1
  /**
2
- * Computes per-glyph quad placements for the given text and style.
2
+ * Compute the bounding pixel dimensions of `text` without allocating quad
3
+ * placements. Returns `{ width: 0, height: 0 }` for empty text.
4
+ */
5
+ function measureText(text, style, provider) {
6
+ if (text.length === 0)
7
+ return { width: 0, height: 0 };
8
+ const { fontSize, lineHeight, leading } = style;
9
+ const computedLineHeight = fontSize * lineHeight + leading;
10
+ const lines = text.split('\n');
11
+ let maxLineWidth = 0;
12
+ for (const line of lines) {
13
+ let lineWidth = 0;
14
+ for (const char of line) {
15
+ lineWidth += provider.getGlyph(char, fontSize).advance;
16
+ }
17
+ if (lineWidth > maxLineWidth)
18
+ maxLineWidth = lineWidth;
19
+ }
20
+ return { width: maxLineWidth, height: lines.length * computedLineHeight };
21
+ }
22
+ /**
23
+ * Computes per-glyph quad placements for the given text, style, and layout
24
+ * options.
3
25
  *
4
- * Handles `\n` line breaks and left/center/right alignment. No word-wrap,
5
- * no RTL, no ligature shaping Unicode/diacritics are delegated to the
6
- * browser's font engine via canvas `fillText`.
26
+ * Handles `\n` line breaks, left/center/right/justify alignment, `letterSpacing`,
27
+ * `leading`, `breakWords`, `whiteSpace` preprocessing, and optional kerning
28
+ * (if the provider implements `getKerning`). RTL and ligature shaping are out
29
+ * of scope; Unicode/diacritics are delegated to the browser's canvas engine.
7
30
  *
8
31
  * Returns an empty array for empty text.
9
32
  */
10
- function layoutText(text, style, atlas) {
11
- if (text.length === 0) {
33
+ function layoutText(text, style, layout, provider) {
34
+ if (text.length === 0)
12
35
  return [];
36
+ const { fontSize, lineHeight, leading, align } = style;
37
+ const computedLineHeight = fontSize * lineHeight + leading;
38
+ const letterSpacing = layout.letterSpacing ?? 0;
39
+ const maxWidth = layout.maxWidth;
40
+ const breakWords = layout.breakWords ?? false;
41
+ const whiteSpace = layout.whiteSpace ?? 'pre-line';
42
+ // ── Whitespace preprocessing ──────────────────────────────────────────────
43
+ const preprocessed = _applyWhiteSpace(text, whiteSpace);
44
+ // Split into hard lines then optionally word-wrap each.
45
+ const hardLines = preprocessed.split('\n');
46
+ const allLines = [];
47
+ for (const hard of hardLines) {
48
+ if (maxWidth === undefined) {
49
+ allLines.push(hard);
50
+ }
51
+ else {
52
+ allLines.push(..._wrapLine(hard, fontSize, provider, maxWidth, letterSpacing, breakWords));
53
+ }
13
54
  }
14
- const { fontSize, fontFamily, fontWeight, fontStyle, lineHeight, align } = style;
15
- const computedLineHeight = fontSize * lineHeight;
16
- const lines = text.split('\n');
17
- // Pass 1: gather glyph info per line, track line widths
55
+ // Pass 1: gather glyph info per line, track widths and word counts.
18
56
  const linePlacements = [];
19
57
  let maxLineWidth = 0;
20
- for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
21
- const line = lines[lineIndex];
22
- const y = lineIndex * computedLineHeight;
58
+ for (let lineIndex = 0; lineIndex < allLines.length; lineIndex++) {
59
+ const line = allLines[lineIndex];
60
+ const lineY = lineIndex * computedLineHeight;
23
61
  let cursorX = 0;
62
+ let wordCount = 0;
63
+ let inWord = false;
24
64
  const placements = [];
65
+ let prevChar = null;
25
66
  for (const char of line) {
26
- const info = atlas.getGlyph(char, fontFamily, fontSize, fontWeight, fontStyle);
27
- placements.push({ info, x: cursorX, y });
28
- cursorX += info.advance;
67
+ // Kerning adjustment before placing this character.
68
+ if (prevChar !== null && provider.getKerning !== undefined) {
69
+ cursorX += provider.getKerning(prevChar, char, fontSize);
70
+ }
71
+ const info = provider.getGlyph(char, fontSize);
72
+ placements.push({ info, x: cursorX, y: lineY, char });
73
+ cursorX += info.advance + letterSpacing;
74
+ if (char === ' ') {
75
+ inWord = false;
76
+ }
77
+ else if (!inWord) {
78
+ inWord = true;
79
+ wordCount++;
80
+ }
81
+ prevChar = char;
29
82
  }
30
- const lineWidth = cursorX;
31
- if (lineWidth > maxLineWidth) {
83
+ const lineWidth = cursorX - (placements.length > 0 ? letterSpacing : 0);
84
+ if (lineWidth > maxLineWidth)
32
85
  maxLineWidth = lineWidth;
33
- }
34
- linePlacements.push({ placements, width: lineWidth });
86
+ linePlacements.push({ placements, width: lineWidth, wordCount });
35
87
  }
36
- // Pass 2: apply alignment and build final GlyphPlacement array
88
+ // Pass 2: apply alignment offset and build final GlyphPlacement array.
37
89
  const result = [];
38
- for (const line of linePlacements) {
90
+ const lastLineIndex = linePlacements.length - 1;
91
+ for (let li = 0; li < linePlacements.length; li++) {
92
+ const line = linePlacements[li];
39
93
  let offsetX = 0;
40
94
  if (align === 'right') {
41
95
  offsetX = maxLineWidth - line.width;
@@ -43,12 +97,42 @@ function layoutText(text, style, atlas) {
43
97
  else if (align === 'center') {
44
98
  offsetX = (maxLineWidth - line.width) / 2;
45
99
  }
100
+ else if (align === 'justify' && li !== lastLineIndex && line.wordCount > 1) {
101
+ // Justify: distribute extra space evenly among inter-word gaps.
102
+ const gaps = line.wordCount - 1;
103
+ const extraPerGap = (maxLineWidth - line.width) / gaps;
104
+ let wordIdx = -1;
105
+ let prevWasSpace = true;
106
+ const spaceAdv = provider.getGlyph(' ', fontSize).advance;
107
+ for (const entry of line.placements) {
108
+ if (prevWasSpace && entry.info.advance !== spaceAdv) {
109
+ wordIdx++;
110
+ prevWasSpace = false;
111
+ }
112
+ else if (!prevWasSpace && entry.info.advance === spaceAdv) {
113
+ prevWasSpace = true;
114
+ }
115
+ result.push({
116
+ x: entry.x + offsetX + wordIdx * extraPerGap + (entry.info.xBearing ?? 0),
117
+ y: entry.y + (entry.info.yBearing ?? 0),
118
+ width: entry.info.width,
119
+ height: entry.info.height,
120
+ page: entry.info.page,
121
+ uvLeft: entry.info.uvLeft,
122
+ uvTop: entry.info.uvTop,
123
+ uvRight: entry.info.uvRight,
124
+ uvBottom: entry.info.uvBottom,
125
+ });
126
+ }
127
+ continue;
128
+ }
46
129
  for (const { info, x, y } of line.placements) {
47
130
  result.push({
48
- x: x + offsetX,
49
- y,
131
+ x: x + offsetX + (info.xBearing ?? 0),
132
+ y: y + (info.yBearing ?? 0),
50
133
  width: info.width,
51
134
  height: info.height,
135
+ page: info.page,
52
136
  uvLeft: info.uvLeft,
53
137
  uvTop: info.uvTop,
54
138
  uvRight: info.uvRight,
@@ -58,6 +142,131 @@ function layoutText(text, style, atlas) {
58
142
  }
59
143
  return result;
60
144
  }
145
+ /**
146
+ * Convert {@link GlyphPlacement} arrays into per-atlas-page quad geometry
147
+ * ready for GPU upload. Zero-size placements (e.g. whitespace glyphs that
148
+ * have no atlas entry) are skipped.
149
+ */
150
+ function buildTextPageQuads(placements) {
151
+ const byPage = new Map();
152
+ for (const p of placements) {
153
+ if (p.width <= 0 || p.height <= 0)
154
+ continue; // skip invisible/whitespace quads
155
+ let arr = byPage.get(p.page);
156
+ if (arr === undefined)
157
+ byPage.set(p.page, (arr = []));
158
+ arr.push(p);
159
+ }
160
+ const result = [];
161
+ for (const [pageIndex, pagePlacements] of byPage) {
162
+ const n = pagePlacements.length;
163
+ const vertices = new Float32Array(n * 8);
164
+ const uvs = new Float32Array(n * 8);
165
+ const indices = new Uint16Array(n * 6);
166
+ for (let i = 0; i < n; i++) {
167
+ const p = pagePlacements[i];
168
+ const v = i * 8;
169
+ const baseV = i * 4;
170
+ const idxBase = i * 6;
171
+ vertices[v + 0] = p.x;
172
+ vertices[v + 1] = p.y;
173
+ vertices[v + 2] = p.x + p.width;
174
+ vertices[v + 3] = p.y;
175
+ vertices[v + 4] = p.x + p.width;
176
+ vertices[v + 5] = p.y + p.height;
177
+ vertices[v + 6] = p.x;
178
+ vertices[v + 7] = p.y + p.height;
179
+ uvs[v + 0] = p.uvLeft;
180
+ uvs[v + 1] = p.uvTop;
181
+ uvs[v + 2] = p.uvRight;
182
+ uvs[v + 3] = p.uvTop;
183
+ uvs[v + 4] = p.uvRight;
184
+ uvs[v + 5] = p.uvBottom;
185
+ uvs[v + 6] = p.uvLeft;
186
+ uvs[v + 7] = p.uvBottom;
187
+ indices[idxBase + 0] = baseV;
188
+ indices[idxBase + 1] = baseV + 1;
189
+ indices[idxBase + 2] = baseV + 2;
190
+ indices[idxBase + 3] = baseV;
191
+ indices[idxBase + 4] = baseV + 2;
192
+ indices[idxBase + 5] = baseV + 3;
193
+ }
194
+ result.push({ pageIndex, vertices, uvs, indices, quadCount: n });
195
+ }
196
+ return result;
197
+ }
198
+ // ── Internal helpers ──────────────────────────────────────────────────────────
199
+ function _applyWhiteSpace(text, mode) {
200
+ if (mode === 'pre')
201
+ return text;
202
+ if (mode === 'normal') {
203
+ return text.replaceAll('\n', ' ').replaceAll(/[ \t]+/g, ' ');
204
+ }
205
+ // 'pre-line': collapse spaces per line, preserve newlines (default)
206
+ return text
207
+ .split('\n')
208
+ .map(line => line.replaceAll(/[ \t]+/g, ' '))
209
+ .join('\n');
210
+ }
211
+ function _wrapLine(line, fontSize, provider, maxWidth, letterSpacing, breakWords) {
212
+ if (line.length === 0)
213
+ return [''];
214
+ const words = line.split(' ');
215
+ const lines = [];
216
+ let current = '';
217
+ let currentWidth = 0;
218
+ const spaceAdv = provider.getGlyph(' ', fontSize).advance + letterSpacing;
219
+ for (const word of words) {
220
+ let wordWidth = 0;
221
+ for (const char of word) {
222
+ wordWidth += provider.getGlyph(char, fontSize).advance + letterSpacing;
223
+ }
224
+ wordWidth = Math.max(0, wordWidth - letterSpacing);
225
+ if (breakWords && wordWidth > maxWidth) {
226
+ if (current.length > 0) {
227
+ lines.push(current);
228
+ current = '';
229
+ currentWidth = 0;
230
+ }
231
+ let charLine = '';
232
+ let charLineWidth = 0;
233
+ for (const char of word) {
234
+ const cw = provider.getGlyph(char, fontSize).advance + letterSpacing;
235
+ if (charLine.length > 0 && charLineWidth + cw > maxWidth) {
236
+ lines.push(charLine);
237
+ charLine = char;
238
+ charLineWidth = cw;
239
+ }
240
+ else {
241
+ charLine += char;
242
+ charLineWidth += cw;
243
+ }
244
+ }
245
+ if (charLine.length > 0) {
246
+ current = charLine;
247
+ currentWidth = charLineWidth;
248
+ }
249
+ }
250
+ else if (current.length === 0) {
251
+ current = word;
252
+ currentWidth = wordWidth;
253
+ }
254
+ else {
255
+ const withSpace = currentWidth + spaceAdv + wordWidth;
256
+ if (withSpace <= maxWidth) {
257
+ current += ` ${word}`;
258
+ currentWidth = withSpace;
259
+ }
260
+ else {
261
+ lines.push(current);
262
+ current = word;
263
+ currentWidth = wordWidth;
264
+ }
265
+ }
266
+ }
267
+ lines.push(current);
268
+ return lines;
269
+ }
61
270
 
62
- export { layoutText };
271
+ export { buildTextPageQuads, layoutText, measureText };
63
272
  //# sourceMappingURL=TextLayout.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextLayout.js","sources":["../../../../../src/rendering/text/TextLayout.ts"],"sourcesContent":[null],"names":[],"mappings":"AAaA;;;;;;;;AAQG;SACa,UAAU,CAAC,IAAY,EAAE,KAAgB,EAAE,KAAwB,EAAA;AACjF,IAAA,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;AACrB,QAAA,OAAO,EAAE;IACX;AAEA,IAAA,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,KAAK;AAChF,IAAA,MAAM,kBAAkB,GAAG,QAAQ,GAAG,UAAU;IAChD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;;IAG9B,MAAM,cAAc,GAAoB,EAAE;IAC1C,IAAI,YAAY,GAAG,CAAC;AAEpB,IAAA,KAAK,IAAI,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE;AAC7D,QAAA,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC;AAC7B,QAAA,MAAM,CAAC,GAAG,SAAS,GAAG,kBAAkB;QACxC,IAAI,OAAO,GAAG,CAAC;QACf,MAAM,UAAU,GAAgC,EAAE;AAElD,QAAA,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE;AACvB,YAAA,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,CAAC;AAE9E,YAAA,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AACxC,YAAA,OAAO,IAAI,IAAI,CAAC,OAAO;QACzB;QAEA,MAAM,SAAS,GAAG,OAAO;AAEzB,QAAA,IAAI,SAAS,GAAG,YAAY,EAAE;YAC5B,YAAY,GAAG,SAAS;QAC1B;QAEA,cAAc,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IACvD;;IAGA,MAAM,MAAM,GAAqB,EAAE;AAEnC,IAAA,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE;QACjC,IAAI,OAAO,GAAG,CAAC;AAEf,QAAA,IAAI,KAAK,KAAK,OAAO,EAAE;AACrB,YAAA,OAAO,GAAG,YAAY,GAAG,IAAI,CAAC,KAAK;QACrC;AAAO,aAAA,IAAI,KAAK,KAAK,QAAQ,EAAE;YAC7B,OAAO,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC;QAC3C;AAEA,QAAA,KAAK,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,IAAI,CAAC,UAAU,EAAE;YAC5C,MAAM,CAAC,IAAI,CAAC;gBACV,CAAC,EAAE,CAAC,GAAG,OAAO;gBACd,CAAC;gBACD,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;AACxB,aAAA,CAAC;QACJ;IACF;AAEA,IAAA,OAAO,MAAM;AACf;;;;"}
1
+ {"version":3,"file":"TextLayout.js","sources":["../../../../../src/rendering/text/TextLayout.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -1,115 +1,182 @@
1
1
  import { Color } from '@/core/Color';
2
+ import { Signal } from '@/core/Signal';
2
3
  import type { TextAlignment } from './types';
3
- /** A CSS color string, canvas gradient, or canvas pattern accepted as fill or stroke. */
4
- export type TextStyleColor = string | CanvasGradient | CanvasPattern;
4
+ export type GradientAxis = 'vertical' | 'horizontal';
5
+ /**
6
+ * Describes how costly a style change is to incorporate.
7
+ *
8
+ * Hints accumulate to the heaviest pending change:
9
+ * `tint` < `layout` < `font`
10
+ */
11
+ export type StyleChangeHint = 'tint' | 'layout' | 'font';
12
+ /**
13
+ * Font weight values accepted by CSS / Canvas 2D.
14
+ */
15
+ export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';
16
+ /**
17
+ * Open interface for compile-time font-family autocomplete via declaration
18
+ * merging. Register loaded font families in your app's `.d.ts`:
19
+ *
20
+ * ```ts
21
+ * declare module 'exojs' {
22
+ * interface FontRegistry {
23
+ * 'AndyBold': true;
24
+ * }
25
+ * }
26
+ * ```
27
+ */
28
+ export interface FontRegistry {
29
+ }
30
+ /**
31
+ * A CSS font-family string. When {@link FontRegistry} has entries the type
32
+ * narrows to registered names ∪ arbitrary strings (for unregistered fonts);
33
+ * without registry entries it falls back to plain `string`.
34
+ */
35
+ export type FontFamily = [keyof FontRegistry] extends [never] ? string : keyof FontRegistry | (string & {});
5
36
  /**
6
37
  * Construction-time options for a {@link TextStyle}.
7
- * All properties are optional; defaults match the {@link TextStyle} constructor defaults.
38
+ * All properties are optional; defaults match the {@link TextStyle} constructor.
8
39
  */
9
40
  export interface TextStyleOptions {
10
- align?: TextAlignment;
11
- fill?: TextStyleColor;
41
+ /**
42
+ * A pre-constructed {@link FontFace} to use as the font for this node.
43
+ *
44
+ * When passed to {@link Text}, the face is automatically registered
45
+ * with `document.fonts`. Load the face via {@link FontFactory} before
46
+ * constructing the node so glyphs render immediately.
47
+ *
48
+ * Takes precedence over `fontFamily` when both are set.
49
+ *
50
+ * ```ts
51
+ * const face = await loader.load(FontFactory, 'roboto.woff2', { family: 'Roboto' });
52
+ * const label = new Text('Score: 0', { font: face, fontSize: 24 });
53
+ * ```
54
+ */
55
+ font?: FontFace;
56
+ fontFamily?: FontFamily;
57
+ fontWeight?: FontWeight;
58
+ fontStyle?: 'normal' | 'italic';
59
+ fontSize?: number;
12
60
  fillColor?: Color;
61
+ outlineColor?: Color;
62
+ /** Outline width in SDF units (0..0.5). 0 disables the outline. */
63
+ outlineWidth?: number;
64
+ align?: TextAlignment;
13
65
  lineHeight?: number;
14
- stroke?: TextStyleColor;
15
- strokeThickness?: number;
16
- fontSize?: number;
17
- fontWeight?: string;
18
- fontFamily?: string;
19
- fontStyle?: 'normal' | 'italic';
20
- wordWrap?: boolean;
21
- wordWrapWidth?: number;
22
- baseline?: CanvasTextBaseline;
23
- lineJoin?: CanvasLineJoin;
24
- miterLimit?: number;
25
- padding?: number;
66
+ /** Extra pixel gap between lines, added on top of `lineHeight`. */
67
+ leading?: number;
68
+ /** Drop-shadow color. */
69
+ shadowColor?: Color;
70
+ /** Horizontal shadow offset in pixels. */
71
+ shadowOffsetX?: number;
72
+ /** Vertical shadow offset in pixels. */
73
+ shadowOffsetY?: number;
74
+ /** Shadow opacity (0..1). 0 disables the shadow. */
75
+ shadowAlpha?: number;
76
+ /** Shadow blur softness (0..1). Larger values soften the shadow edge. */
77
+ shadowBlur?: number;
78
+ /**
79
+ * Two-stop fill gradient `[top, bottom]`. When set, overrides `fillColor`
80
+ * for the glyph interior. `null` disables the gradient.
81
+ */
82
+ gradientColors?: [Color, Color] | null;
83
+ /** Gradient orientation. Defaults to `'vertical'`. */
84
+ gradientAxis?: GradientAxis;
26
85
  }
27
86
  /**
28
- * Immutable-style value bag that describes how a {@link Text} node should
29
- * render its string. Every property setter marks the style as `dirty` so
30
- * that the owning Text can detect changes and rebuild its glyph mesh.
87
+ * Describes how a {@link Text} node renders its string.
31
88
  *
32
- * Glyphs are always rasterized in white; `fillColor` is applied as a
33
- * `Mesh.tint` multiplier at draw time, so changing it never triggers
34
- * atlas re-rasterization. The canvas `fill` / `stroke` properties are
35
- * used only during glyph rasterization itself.
89
+ * Every setter marks the style dirty with a {@link StyleChangeHint} so that
90
+ * the owning node can batch-rebuild efficiently on the next frame:
91
+ * - `'tint'` only updates `Mesh.tint`, no atlas work
92
+ * - `'layout'` rebuilds the glyph mesh, reuses cached atlas glyphs
93
+ * - `'font'` — atlas lookup + full mesh rebuild
94
+ *
95
+ * Call {@link consumeDirty} at the start of each frame to get the accumulated
96
+ * hint and clear the flag.
36
97
  */
37
98
  export declare class TextStyle {
38
- private _align;
39
- private _fill;
40
- private _fillColor;
41
- private _lineHeight;
42
- private _stroke;
43
- private _strokeThickness;
44
- private _fontSize;
45
- private _fontWeight;
99
+ private _dirty;
100
+ private _pendingHint;
101
+ /** Fires once per dirty cycle when any property changes. */
102
+ readonly onChange: Signal<[]>;
46
103
  private _fontFamily;
104
+ private _fontWeight;
47
105
  private _fontStyle;
48
- private _wordWrap;
49
- private _wordWrapWidth;
50
- private _baseline;
51
- private _lineJoin;
52
- private _miterLimit;
53
- private _padding;
54
- private _dirty;
106
+ private _fontSize;
107
+ private _fillColor;
108
+ private _outlineColor;
109
+ private _outlineWidth;
110
+ private _align;
111
+ private _lineHeight;
112
+ private _leading;
113
+ private _shadowColor;
114
+ private _shadowOffsetX;
115
+ private _shadowOffsetY;
116
+ private _shadowAlpha;
117
+ private _shadowBlur;
118
+ private _gradientColors;
119
+ private _gradientAxis;
55
120
  constructor(options?: TextStyleOptions);
56
- get align(): TextAlignment;
57
- set align(align: TextAlignment);
58
- get fill(): TextStyleColor;
59
- set fill(fill: TextStyleColor);
60
121
  /**
61
- * Runtime fill color applied via `Mesh.tint`. Glyphs are always
62
- * rasterized white; this color multiplies them at draw time so that
63
- * changing the color never requires re-rasterizing cached glyphs.
122
+ * Returns the accumulated {@link StyleChangeHint} and clears the dirty flag,
123
+ * or `null` if nothing has changed since the last call.
124
+ *
125
+ * Call this once per frame from the owning node's `update()` method.
64
126
  */
65
- get fillColor(): Color;
66
- set fillColor(color: Color);
67
- /**
68
- * Line-height multiplier applied to `fontSize` when computing vertical
69
- * spacing between lines. Defaults to 1.2.
70
- */
71
- get lineHeight(): number;
72
- set lineHeight(lineHeight: number);
73
- get stroke(): TextStyleColor;
74
- set stroke(stroke: TextStyleColor);
75
- get strokeThickness(): number;
76
- set strokeThickness(strokeThickness: number);
77
- get fontSize(): number;
78
- set fontSize(fontSize: number);
79
- get fontWeight(): string;
80
- set fontWeight(fontWeight: string);
81
- get fontFamily(): string;
82
- set fontFamily(fontFamily: string);
127
+ consumeDirty(): StyleChangeHint | null;
128
+ private _markDirty;
129
+ get fontFamily(): FontFamily;
130
+ set fontFamily(v: FontFace | FontFamily);
131
+ get fontWeight(): FontWeight;
132
+ set fontWeight(v: FontWeight);
83
133
  get fontStyle(): 'normal' | 'italic';
84
- set fontStyle(fontStyle: 'normal' | 'italic');
85
- get wordWrap(): boolean;
86
- set wordWrap(wordWrap: boolean);
87
- get wordWrapWidth(): number;
88
- set wordWrapWidth(wordWrapWidth: number);
89
- get baseline(): CanvasTextBaseline;
90
- set baseline(baseline: CanvasTextBaseline);
91
- get lineJoin(): CanvasLineJoin;
92
- set lineJoin(lineJoin: CanvasLineJoin);
93
- get miterLimit(): number;
94
- set miterLimit(miterLimit: number);
95
- get padding(): number;
96
- set padding(padding: number);
134
+ set fontStyle(v: 'normal' | 'italic');
135
+ get fontSize(): number;
136
+ set fontSize(v: number);
137
+ get align(): TextAlignment;
138
+ set align(v: TextAlignment);
139
+ get lineHeight(): number;
140
+ set lineHeight(v: number);
141
+ /** Extra pixel gap between lines, added on top of `lineHeight`. */
142
+ get leading(): number;
143
+ set leading(v: number);
97
144
  /**
98
- * Whether any property has changed since the last time this flag was
99
- * cleared. {@link Text} reads this to decide whether to rebuild its mesh.
145
+ * Runtime fill color applied as `Mesh.tint`. Glyphs are always rasterized
146
+ * white; this color multiplies them at draw time without touching the atlas.
100
147
  */
101
- get dirty(): boolean;
102
- set dirty(dirty: boolean);
148
+ get fillColor(): Color;
149
+ set fillColor(v: Color);
150
+ /** Outline color — used by BitmapText/SDF rendering as a shader uniform. */
151
+ get outlineColor(): Color;
152
+ set outlineColor(v: Color);
153
+ /** Outline width in SDF units (0..0.5). `0` disables the outline. */
154
+ get outlineWidth(): number;
155
+ set outlineWidth(v: number);
156
+ get shadowColor(): Color;
157
+ set shadowColor(v: Color);
158
+ get shadowOffsetX(): number;
159
+ set shadowOffsetX(v: number);
160
+ get shadowOffsetY(): number;
161
+ set shadowOffsetY(v: number);
162
+ /** Shadow opacity (0..1). `0` disables the shadow. */
163
+ get shadowAlpha(): number;
164
+ set shadowAlpha(v: number);
165
+ get shadowBlur(): number;
166
+ set shadowBlur(v: number);
103
167
  /**
104
- * CSS font string derived from `fontWeight`, `fontSize`, and `fontFamily`.
105
- * Used as `CanvasRenderingContext2D.font` during glyph rasterization.
168
+ * Two-stop fill gradient `[top, bottom]`. When set, overrides `fillColor`
169
+ * for the glyph interior. Assign `null` to disable.
106
170
  */
107
- get font(): string;
171
+ get gradientColors(): [Color, Color] | null;
172
+ set gradientColors(v: [Color, Color] | null);
173
+ get gradientAxis(): GradientAxis;
174
+ set gradientAxis(v: GradientAxis);
108
175
  /**
109
- * Apply this style's properties to a canvas 2D context so the next
110
- * `fillText` / `strokeText` call uses the correct font, color, and stroke.
176
+ * CSS font string used as `CanvasRenderingContext2D.font` during glyph
177
+ * rasterization. Includes `fontStyle` so italic fonts render correctly.
111
178
  */
112
- apply(context: CanvasRenderingContext2D): this;
179
+ get font(): string;
113
180
  /** Copy all properties from `style` into this instance and return `this`. */
114
181
  copy(style: TextStyle): this;
115
182
  /** Return a new {@link TextStyle} with all properties copied from this one. */