visualfries 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +213 -0
  3. package/dist/DIContainer.d.ts +4 -0
  4. package/dist/DIContainer.js +145 -0
  5. package/dist/SceneBuilder.svelte.d.ts +8574 -0
  6. package/dist/SceneBuilder.svelte.js +409 -0
  7. package/dist/adapters/subtitleHelpers.d.ts +2 -0
  8. package/dist/adapters/subtitleHelpers.js +187 -0
  9. package/dist/animations/AnimationContext.d.ts +17 -0
  10. package/dist/animations/AnimationContext.js +72 -0
  11. package/dist/animations/AnimationPresetsRegister.d.ts +362 -0
  12. package/dist/animations/AnimationPresetsRegister.js +20 -0
  13. package/dist/animations/AnimationSetup.d.ts +8 -0
  14. package/dist/animations/AnimationSetup.js +30 -0
  15. package/dist/animations/SplitTextCache.d.ts +28 -0
  16. package/dist/animations/SplitTextCache.js +68 -0
  17. package/dist/animations/animationBuilder.d.ts +31 -0
  18. package/dist/animations/animationBuilder.js +255 -0
  19. package/dist/animations/animationPreset.d.ts +7 -0
  20. package/dist/animations/animationPreset.js +31 -0
  21. package/dist/animations/builders/AnimationPresetFactory.d.ts +43 -0
  22. package/dist/animations/builders/AnimationPresetFactory.js +139 -0
  23. package/dist/animations/builders/LineHighlighterAnimationBuilder.d.ts +16 -0
  24. package/dist/animations/builders/LineHighlighterAnimationBuilder.js +183 -0
  25. package/dist/animations/builders/WordHighlighterAnimationBuilder.d.ts +15 -0
  26. package/dist/animations/builders/WordHighlighterAnimationBuilder.js +180 -0
  27. package/dist/animations/engines/AnimationEngineAdaptor.d.ts +107 -0
  28. package/dist/animations/engines/AnimationEngineAdaptor.js +1 -0
  29. package/dist/animations/engines/GSAPEngineAdaptor.d.ts +21 -0
  30. package/dist/animations/engines/GSAPEngineAdaptor.js +145 -0
  31. package/dist/animations/presets/index.d.ts +2 -0
  32. package/dist/animations/presets/index.js +3 -0
  33. package/dist/animations/presets/lines.d.ts +52 -0
  34. package/dist/animations/presets/lines.js +547 -0
  35. package/dist/animations/presets/words.d.ts +31 -0
  36. package/dist/animations/presets/words.js +268 -0
  37. package/dist/animations/transformers/AnimationReferenceTransformer.d.ts +9 -0
  38. package/dist/animations/transformers/AnimationReferenceTransformer.js +114 -0
  39. package/dist/builders/PixiComponentBuilder.d.ts +63 -0
  40. package/dist/builders/PixiComponentBuilder.js +112 -0
  41. package/dist/builders/_ComponentState.svelte.d.ts +795 -0
  42. package/dist/builders/_ComponentState.svelte.js +203 -0
  43. package/dist/builders/html/HtmlBuilder.d.ts +66 -0
  44. package/dist/builders/html/HtmlBuilder.js +171 -0
  45. package/dist/builders/html/HtmlBuilderFactory.d.ts +27 -0
  46. package/dist/builders/html/HtmlBuilderFactory.js +30 -0
  47. package/dist/builders/html/StyleBuilder.d.ts +13 -0
  48. package/dist/builders/html/StyleBuilder.js +133 -0
  49. package/dist/builders/html/StyleProcessor.d.ts +9 -0
  50. package/dist/builders/html/StyleProcessor.js +1 -0
  51. package/dist/builders/html/TextComponentHtmlBuilder.d.ts +16 -0
  52. package/dist/builders/html/TextComponentHtmlBuilder.js +93 -0
  53. package/dist/builders/html/TextShadowBuilder.d.ts +60 -0
  54. package/dist/builders/html/TextShadowBuilder.js +227 -0
  55. package/dist/builders/html/processors/AppearanceStyleProcessor.d.ts +5 -0
  56. package/dist/builders/html/processors/AppearanceStyleProcessor.js +57 -0
  57. package/dist/builders/html/processors/TextAppearanceStyleProcessor.d.ts +5 -0
  58. package/dist/builders/html/processors/TextAppearanceStyleProcessor.js +37 -0
  59. package/dist/builders/html/processors/TextEffectsStyleProcessor.d.ts +6 -0
  60. package/dist/builders/html/processors/TextEffectsStyleProcessor.js +68 -0
  61. package/dist/commands/Command.d.ts +6 -0
  62. package/dist/commands/Command.js +1 -0
  63. package/dist/commands/CommandRunner.d.ts +28 -0
  64. package/dist/commands/CommandRunner.js +81 -0
  65. package/dist/commands/CommandTypes.d.ts +11 -0
  66. package/dist/commands/CommandTypes.js +13 -0
  67. package/dist/commands/PauseCommand.d.ts +4 -0
  68. package/dist/commands/PauseCommand.js +5 -0
  69. package/dist/commands/PlayCommand.d.ts +4 -0
  70. package/dist/commands/PlayCommand.js +6 -0
  71. package/dist/commands/RenderCommand.d.ts +15 -0
  72. package/dist/commands/RenderCommand.js +18 -0
  73. package/dist/commands/RenderFrameCommand.d.ts +17 -0
  74. package/dist/commands/RenderFrameCommand.js +93 -0
  75. package/dist/commands/ReplaceSourceOnTimeCommand.d.ts +4 -0
  76. package/dist/commands/ReplaceSourceOnTimeCommand.js +22 -0
  77. package/dist/commands/SeekCommand.d.ts +15 -0
  78. package/dist/commands/SeekCommand.js +39 -0
  79. package/dist/commands/UpdateComponentCommand.d.ts +4 -0
  80. package/dist/commands/UpdateComponentCommand.js +17 -0
  81. package/dist/components/AnimatedGIF.d.ts +201 -0
  82. package/dist/components/AnimatedGIF.js +391 -0
  83. package/dist/components/Component.svelte.d.ts +33 -0
  84. package/dist/components/Component.svelte.js +152 -0
  85. package/dist/components/ComponentContext.svelte.d.ts +33 -0
  86. package/dist/components/ComponentContext.svelte.js +105 -0
  87. package/dist/components/hooks/AnimationHook.d.ts +25 -0
  88. package/dist/components/hooks/AnimationHook.js +180 -0
  89. package/dist/components/hooks/CanvasShapeHook.d.ts +12 -0
  90. package/dist/components/hooks/CanvasShapeHook.js +229 -0
  91. package/dist/components/hooks/HtmlAnimationHook.d.ts +8 -0
  92. package/dist/components/hooks/HtmlAnimationHook.js +70 -0
  93. package/dist/components/hooks/HtmlTextHook.d.ts +16 -0
  94. package/dist/components/hooks/HtmlTextHook.js +102 -0
  95. package/dist/components/hooks/HtmlToCanvasHook.d.ts +16 -0
  96. package/dist/components/hooks/HtmlToCanvasHook.js +148 -0
  97. package/dist/components/hooks/ImageHook.d.ts +10 -0
  98. package/dist/components/hooks/ImageHook.js +45 -0
  99. package/dist/components/hooks/MediaHook.d.ts +15 -0
  100. package/dist/components/hooks/MediaHook.js +252 -0
  101. package/dist/components/hooks/MediaSeekingHook.d.ts +12 -0
  102. package/dist/components/hooks/MediaSeekingHook.js +204 -0
  103. package/dist/components/hooks/PixiDisplayObjectHook.d.ts +15 -0
  104. package/dist/components/hooks/PixiDisplayObjectHook.js +77 -0
  105. package/dist/components/hooks/PixiGifHook.d.ts +15 -0
  106. package/dist/components/hooks/PixiGifHook.js +97 -0
  107. package/dist/components/hooks/PixiProgressShapeHook.d.ts +12 -0
  108. package/dist/components/hooks/PixiProgressShapeHook.js +128 -0
  109. package/dist/components/hooks/PixiSplitScreenDisplayObjectHook.d.ts +21 -0
  110. package/dist/components/hooks/PixiSplitScreenDisplayObjectHook.js +210 -0
  111. package/dist/components/hooks/PixiTextureHook.d.ts +7 -0
  112. package/dist/components/hooks/PixiTextureHook.js +29 -0
  113. package/dist/components/hooks/PixiVideoTextureHook.d.ts +10 -0
  114. package/dist/components/hooks/PixiVideoTextureHook.js +35 -0
  115. package/dist/components/hooks/SubtitlesHook.d.ts +88 -0
  116. package/dist/components/hooks/SubtitlesHook.js +199 -0
  117. package/dist/components/hooks/VerifyGifHook.d.ts +7 -0
  118. package/dist/components/hooks/VerifyGifHook.js +27 -0
  119. package/dist/components/hooks/VerifyImageHook.d.ts +7 -0
  120. package/dist/components/hooks/VerifyImageHook.js +27 -0
  121. package/dist/components/hooks/VerifyMediaHook.d.ts +7 -0
  122. package/dist/components/hooks/VerifyMediaHook.js +21 -0
  123. package/dist/components/hooks/shapes/progress/CustomProgressRenderer.d.ts +8 -0
  124. package/dist/components/hooks/shapes/progress/CustomProgressRenderer.js +53 -0
  125. package/dist/components/hooks/shapes/progress/DoubleProgressRenderer.d.ts +8 -0
  126. package/dist/components/hooks/shapes/progress/DoubleProgressRenderer.js +69 -0
  127. package/dist/components/hooks/shapes/progress/LinearProgressRenderer.d.ts +8 -0
  128. package/dist/components/hooks/shapes/progress/LinearProgressRenderer.js +60 -0
  129. package/dist/components/hooks/shapes/progress/PerimeterProgressRenderer.d.ts +9 -0
  130. package/dist/components/hooks/shapes/progress/PerimeterProgressRenderer.js +213 -0
  131. package/dist/components/hooks/shapes/progress/ProgressRenderer.d.ts +17 -0
  132. package/dist/components/hooks/shapes/progress/ProgressRenderer.js +75 -0
  133. package/dist/components/hooks/shapes/progress/RadialProgressRenderer.d.ts +8 -0
  134. package/dist/components/hooks/shapes/progress/RadialProgressRenderer.js +50 -0
  135. package/dist/components/hooks/shapes/progress/index.d.ts +6 -0
  136. package/dist/components/hooks/shapes/progress/index.js +6 -0
  137. package/dist/composers/componentComposer.d.ts +55 -0
  138. package/dist/composers/componentComposer.js +118 -0
  139. package/dist/composers/layerComposer.d.ts +46 -0
  140. package/dist/composers/layerComposer.js +79 -0
  141. package/dist/composers/sceneComposer.d.ts +48 -0
  142. package/dist/composers/sceneComposer.js +92 -0
  143. package/dist/constants.d.ts +12 -0
  144. package/dist/constants.js +14 -0
  145. package/dist/directors/ComponentDirector.d.ts +20 -0
  146. package/dist/directors/ComponentDirector.js +86 -0
  147. package/dist/factories/SceneBuilderFactory.d.ts +15 -0
  148. package/dist/factories/SceneBuilderFactory.js +51 -0
  149. package/dist/fonts/GoogleFontsProvider.d.ts +12 -0
  150. package/dist/fonts/GoogleFontsProvider.js +125 -0
  151. package/dist/fonts/fontLoader.d.ts +15 -0
  152. package/dist/fonts/fontLoader.js +41 -0
  153. package/dist/fonts/types.d.ts +1 -0
  154. package/dist/fonts/types.js +1 -0
  155. package/dist/index.d.ts +11 -0
  156. package/dist/index.js +14 -0
  157. package/dist/layers/Layer.svelte.d.ts +8492 -0
  158. package/dist/layers/Layer.svelte.js +125 -0
  159. package/dist/managers/AppManager.svelte.d.ts +23 -0
  160. package/dist/managers/AppManager.svelte.js +89 -0
  161. package/dist/managers/ComponentsManager.svelte.d.ts +49 -0
  162. package/dist/managers/ComponentsManager.svelte.js +247 -0
  163. package/dist/managers/DomManager.d.ts +18 -0
  164. package/dist/managers/DomManager.js +73 -0
  165. package/dist/managers/EventManager.d.ts +7 -0
  166. package/dist/managers/EventManager.js +22 -0
  167. package/dist/managers/LayersManager.svelte.d.ts +8499 -0
  168. package/dist/managers/LayersManager.svelte.js +176 -0
  169. package/dist/managers/MediaManager.d.ts +32 -0
  170. package/dist/managers/MediaManager.js +243 -0
  171. package/dist/managers/RenderManager.d.ts +23 -0
  172. package/dist/managers/RenderManager.js +59 -0
  173. package/dist/managers/StateManager.svelte.d.ts +8746 -0
  174. package/dist/managers/StateManager.svelte.js +272 -0
  175. package/dist/managers/SubtitlesManager.svelte.d.ts +261 -0
  176. package/dist/managers/SubtitlesManager.svelte.js +1385 -0
  177. package/dist/managers/TimeManager.svelte.d.ts +6 -0
  178. package/dist/managers/TimeManager.svelte.js +18 -0
  179. package/dist/managers/TimelineManager.svelte.d.ts +25 -0
  180. package/dist/managers/TimelineManager.svelte.js +152 -0
  181. package/dist/registers.d.ts +12 -0
  182. package/dist/registers.js +29 -0
  183. package/dist/schemas/runtime/index.d.ts +3 -0
  184. package/dist/schemas/runtime/index.js +4 -0
  185. package/dist/schemas/runtime/types.d.ts +323 -0
  186. package/dist/schemas/runtime/types.js +12 -0
  187. package/dist/schemas/scene/animations.d.ts +89738 -0
  188. package/dist/schemas/scene/animations.js +211 -0
  189. package/dist/schemas/scene/components.js +515 -0
  190. package/dist/schemas/scene/core.js +160 -0
  191. package/dist/schemas/scene/index.d.ts +22 -0
  192. package/dist/schemas/scene/index.js +10 -0
  193. package/dist/schemas/scene/properties.d.ts +914 -0
  194. package/dist/schemas/scene/properties.js +398 -0
  195. package/dist/schemas/scene/subtitles.d.ts +1141 -0
  196. package/dist/schemas/scene/subtitles.js +111 -0
  197. package/dist/schemas/scene/utils.d.ts +1 -0
  198. package/dist/schemas/scene/utils.js +5 -0
  199. package/dist/seeds/SeedFactory.d.ts +59 -0
  200. package/dist/seeds/SeedFactory.js +99 -0
  201. package/dist/seeds/index.d.ts +8 -0
  202. package/dist/seeds/index.js +8 -0
  203. package/dist/transformers/ColorTransformer.d.ts +5 -0
  204. package/dist/transformers/ColorTransformer.js +67 -0
  205. package/dist/transformers/PixiColorTransformer.d.ts +22 -0
  206. package/dist/transformers/PixiColorTransformer.js +104 -0
  207. package/dist/utils/canvas.d.ts +6 -0
  208. package/dist/utils/canvas.js +18 -0
  209. package/dist/utils/document.d.ts +2 -0
  210. package/dist/utils/document.js +36 -0
  211. package/dist/utils/emoji.d.ts +10 -0
  212. package/dist/utils/emoji.js +51 -0
  213. package/dist/utils/html.d.ts +4 -0
  214. package/dist/utils/html.js +45 -0
  215. package/dist/utils/svgGenerator.d.ts +20 -0
  216. package/dist/utils/svgGenerator.js +103 -0
  217. package/dist/utils/utils.d.ts +5 -0
  218. package/dist/utils/utils.js +125 -0
  219. package/package.json +96 -0
@@ -0,0 +1,210 @@
1
+ import * as PIXI from 'pixi.js-legacy';
2
+ import { LayoutSplitEffectShape, VideoComponentShape } from '../..';
3
+ import { z } from 'zod';
4
+ export class PixiSplitScreenDisplayObjectHook {
5
+ types = ['update', 'destroy', 'refresh'];
6
+ #handlers = {
7
+ update: this.#handleUpdate.bind(this),
8
+ destroy: this.#handleDestroy.bind(this),
9
+ refresh: this.#handleRefresh.bind(this),
10
+ 'refresh:config': this.#handleRefresh.bind(this),
11
+ 'refresh:metadata': this.#handleRefresh.bind(this)
12
+ };
13
+ priority = 1;
14
+ #context;
15
+ #pixiTexture;
16
+ #displayObject;
17
+ #bgCanvas = undefined;
18
+ componentElement;
19
+ sceneState;
20
+ constructor(cradle) {
21
+ this.sceneState = cradle.stateManager;
22
+ }
23
+ get sceneWidth() {
24
+ return this.#context.sceneState.width;
25
+ }
26
+ get sceneHeight() {
27
+ return this.#context.sceneState.height;
28
+ }
29
+ initBlurBackground(strength = 50) {
30
+ const sanitizedStrength = this.#sanitizeBlurStrength(strength);
31
+ const backgroundSprite = new PIXI.Sprite(this.#pixiTexture);
32
+ this.setupBackground(backgroundSprite, sanitizedStrength);
33
+ this.#displayObject.addChild(backgroundSprite);
34
+ }
35
+ setupBackground(backgroundSprite, strength = 50) {
36
+ const sanitizedStrength = this.#sanitizeBlurStrength(strength);
37
+ const sceneRatio = this.sceneWidth / this.sceneHeight;
38
+ const videoRatio = this.#pixiTexture.width / this.#pixiTexture.height;
39
+ let scale;
40
+ if (sceneRatio > videoRatio) {
41
+ // Scene is wider than video
42
+ scale = this.sceneWidth / this.#pixiTexture.width;
43
+ }
44
+ else {
45
+ // Scene is taller than video
46
+ scale = this.sceneHeight / this.#pixiTexture.height;
47
+ }
48
+ backgroundSprite.width = this.#pixiTexture.width * scale;
49
+ backgroundSprite.height = this.#pixiTexture.height * scale;
50
+ // Center the background sprite
51
+ backgroundSprite.x = (this.sceneWidth - backgroundSprite.width) / 2;
52
+ backgroundSprite.y = (this.sceneHeight - backgroundSprite.height) / 2;
53
+ if (this.sceneState.environment === 'server') {
54
+ // Create a temporary canvas for blur effect
55
+ const bgCanvas = document.createElement('canvas');
56
+ bgCanvas.width = backgroundSprite.width;
57
+ bgCanvas.height = backgroundSprite.height;
58
+ this.#bgCanvas = bgCanvas;
59
+ this.#drawBlurredBackground(sanitizedStrength);
60
+ const blurredTexture = PIXI.Texture.from(bgCanvas);
61
+ backgroundSprite.texture = blurredTexture;
62
+ }
63
+ else {
64
+ // Create new PIXI texture from blurred canvas
65
+ const blurFilter = new PIXI.BlurFilter(sanitizedStrength, 50, 1, 7);
66
+ backgroundSprite.filters = [blurFilter];
67
+ }
68
+ }
69
+ #drawBlurredBackground(strength = 50) {
70
+ if (!this.#bgCanvas) {
71
+ return;
72
+ }
73
+ // Validate and sanitize strength parameter
74
+ const sanitizedStrength = this.#sanitizeBlurStrength(strength);
75
+ const ctx = this.#bgCanvas.getContext('2d');
76
+ // Use sanitized value to prevent XSS
77
+ ctx.filter = `blur(${sanitizedStrength}px)`;
78
+ // Get the source element (video/image)
79
+ const sourceElement = this.#context.getResource('videoElement');
80
+ if (!sourceElement) {
81
+ throw new Error('videoElement not found in resources.');
82
+ }
83
+ // const sourceElement = this.#pixiTexture.baseTexture.resource.source as
84
+ // | HTMLVideoElement
85
+ // | HTMLImageElement;
86
+ // Draw the original texture with blur
87
+ ctx.drawImage(sourceElement, 0, 0, this.#bgCanvas.width, this.#bgCanvas.height);
88
+ }
89
+ /**
90
+ * Sanitizes blur strength parameter to prevent XSS and ensure valid numeric values
91
+ * @param strength - The blur strength value to sanitize
92
+ * @returns A safe numeric value between 0 and 100
93
+ */
94
+ #sanitizeBlurStrength(strength) {
95
+ // Convert to number if it's a string
96
+ let numericStrength;
97
+ if (typeof strength === 'string') {
98
+ // Remove any non-numeric characters except decimal point and minus sign
99
+ const cleaned = strength.replace(/[^0-9.-]/g, '');
100
+ numericStrength = parseInt(cleaned);
101
+ }
102
+ else if (typeof strength === 'number') {
103
+ numericStrength = strength;
104
+ }
105
+ else {
106
+ // Default to 50 for any other type
107
+ numericStrength = 50;
108
+ }
109
+ // Check if the result is a valid number
110
+ if (isNaN(numericStrength) || !isFinite(numericStrength)) {
111
+ numericStrength = 50;
112
+ }
113
+ // Clamp the value to a reasonable range (0-100)
114
+ return Math.max(0, Math.min(100, numericStrength));
115
+ }
116
+ initSplitScreen(splitInfo) {
117
+ const containers = [];
118
+ splitInfo.chunks?.forEach((chunk) => {
119
+ // toto nam urobi ohraniceny ramec v ktorom sa ukaze sprite
120
+ const maskGraphics = new PIXI.Graphics();
121
+ maskGraphics.beginFill(0xffffff, 0.5);
122
+ maskGraphics.drawRect(0, 0, chunk.group.width, chunk.group.height);
123
+ maskGraphics.endFill();
124
+ // sprite teraz musime napozicovat do ohraniceneho rameca tak aby bolo cele prekryte a len to co chce user vidiet
125
+ const splitSprite = new PIXI.Sprite(this.#pixiTexture);
126
+ splitSprite.x = chunk.component.x;
127
+ splitSprite.y = chunk.component.y;
128
+ splitSprite.width = chunk.component.width;
129
+ splitSprite.height = chunk.component.height;
130
+ const container = new PIXI.Container();
131
+ container.x = chunk.group.x;
132
+ container.y = chunk.group.y;
133
+ container.mask = maskGraphics;
134
+ container.addChild(splitSprite);
135
+ container.addChild(maskGraphics);
136
+ containers.push(container);
137
+ });
138
+ this.#displayObject.addChild(...containers);
139
+ }
140
+ initMainSprite() {
141
+ const appearance = this.#context.data.appearance;
142
+ const mainSprite = new PIXI.Sprite(this.#pixiTexture);
143
+ mainSprite.width = appearance.width;
144
+ mainSprite.height = appearance.height;
145
+ mainSprite.x = appearance.x;
146
+ mainSprite.y = appearance.y;
147
+ this.#displayObject.addChild(mainSprite);
148
+ }
149
+ #initDisplayObject() {
150
+ if (this.#context.data.effects && !this.#context.data.effects.enabled) {
151
+ this.initMainSprite();
152
+ return;
153
+ }
154
+ const hasBlur = Object.keys(this.#context.data.effects.map).includes('fillBackgroundBlur');
155
+ if (hasBlur) {
156
+ const blurEffect = this.#context.data.effects.map.fillBackgroundBlur;
157
+ const strength = blurEffect?.blurAmount || 50;
158
+ this.initBlurBackground(strength);
159
+ }
160
+ const splitScreen = Object.values(this.#context.data.effects.map).find((key) => key.type === 'layoutSplit');
161
+ const splitScreenInfo = LayoutSplitEffectShape.safeParse(splitScreen);
162
+ if (splitScreenInfo.success) {
163
+ this.initSplitScreen(splitScreenInfo.data);
164
+ return;
165
+ }
166
+ this.initMainSprite();
167
+ }
168
+ async #handleUpdate() {
169
+ const isActive = this.#context.isActive;
170
+ if (isActive) {
171
+ this.#drawBlurredBackground();
172
+ }
173
+ if (this.#displayObject) {
174
+ if (this.#displayObject.visible != isActive) {
175
+ this.#displayObject.visible = isActive;
176
+ }
177
+ return;
178
+ }
179
+ const texture = this.#context.getResource('pixiTexture');
180
+ if (!texture) {
181
+ throw new Error('pixiTexture not found in resources.');
182
+ }
183
+ this.#pixiTexture = texture;
184
+ this.#displayObject = new PIXI.Container();
185
+ this.#initDisplayObject();
186
+ this.#context.setResource('pixiRenderObject', this.#displayObject);
187
+ }
188
+ async #handleRefresh() {
189
+ await this.#handleDestroy();
190
+ this.#displayObject.removeChildren();
191
+ this.#initDisplayObject();
192
+ await this.#handleUpdate();
193
+ }
194
+ async #handleDestroy() {
195
+ // remove event listeners from video
196
+ this.#bgCanvas = undefined;
197
+ }
198
+ async handle(type, context) {
199
+ this.#context = context;
200
+ const data = this.#context.contextData;
201
+ if (!data || data.type !== 'VIDEO') {
202
+ return;
203
+ }
204
+ this.componentElement = data;
205
+ const handler = this.#handlers[type];
206
+ if (handler) {
207
+ await handler();
208
+ }
209
+ }
210
+ }
@@ -0,0 +1,7 @@
1
+ import type { IComponentContext, IComponentHook, HookType } from '../..';
2
+ export declare class PixiTextureHook implements IComponentHook {
3
+ #private;
4
+ types: HookType[];
5
+ priority: number;
6
+ handle(type: HookType, context: IComponentContext): Promise<void>;
7
+ }
@@ -0,0 +1,29 @@
1
+ import * as PIXI from 'pixi.js-legacy';
2
+ // import { setPlacement } from '../../utils/utils.js';
3
+ export class PixiTextureHook {
4
+ types = ['update'];
5
+ priority = 1;
6
+ #context;
7
+ #texture;
8
+ async #handleUpdate() {
9
+ const resource = this.#context.getResource('pixiResource');
10
+ if (!resource) {
11
+ throw new Error('pixiResource not found in resources.');
12
+ }
13
+ if (this.#texture && this.#context.getResource('pixiTexture') === this.#texture) {
14
+ return;
15
+ }
16
+ const texture = PIXI.Texture.from(resource);
17
+ if (texture) {
18
+ this.#context.setResource('pixiTexture', texture);
19
+ this.#texture = texture;
20
+ }
21
+ else {
22
+ throw new Error('Failed to create texture from resource.');
23
+ }
24
+ }
25
+ async handle(type, context) {
26
+ this.#context = context;
27
+ return await this.#handleUpdate();
28
+ }
29
+ }
@@ -0,0 +1,10 @@
1
+ import type { IComponentContext, IComponentHook, HookType } from '../..';
2
+ import { VideoComponentShape } from '../..';
3
+ import { z } from 'zod';
4
+ export declare class PixiVideoTextureHook implements IComponentHook {
5
+ #private;
6
+ types: HookType[];
7
+ priority: number;
8
+ componentElement: z.infer<typeof VideoComponentShape>;
9
+ handle(type: HookType, context: IComponentContext): Promise<void>;
10
+ }
@@ -0,0 +1,35 @@
1
+ import * as PIXI from 'pixi.js-legacy';
2
+ import { VideoComponentShape } from '../..';
3
+ import { z } from 'zod';
4
+ export class PixiVideoTextureHook {
5
+ types = ['update'];
6
+ priority = 1;
7
+ #context;
8
+ #videoTexture;
9
+ componentElement;
10
+ async #handleUpdate() {
11
+ if (this.#videoTexture) {
12
+ return;
13
+ }
14
+ const media = this.#context.getResource('videoElement');
15
+ if (!media) {
16
+ throw new Error('videoElement not found in resources.');
17
+ }
18
+ const res = new PIXI.VideoResource(media, {
19
+ autoPlay: false,
20
+ updateFPS: 30
21
+ });
22
+ const baseTexture = new PIXI.BaseTexture(res);
23
+ this.#videoTexture = new PIXI.Texture(baseTexture);
24
+ this.#context.setResource('pixiTexture', this.#videoTexture);
25
+ }
26
+ async handle(type, context) {
27
+ this.#context = context;
28
+ const data = this.#context.contextData;
29
+ if (!data || data.type !== 'VIDEO') {
30
+ return;
31
+ }
32
+ this.componentElement = data;
33
+ return await this.#handleUpdate();
34
+ }
35
+ }
@@ -0,0 +1,88 @@
1
+ import type { HookType, IComponentContext, IComponentHook } from '../..';
2
+ import type { StateManager } from '../../managers/StateManager.svelte.ts';
3
+ import type { SubtitlesManager } from '../../managers/SubtitlesManager.svelte.ts';
4
+ import type { EventManager } from '../../managers/EventManager.ts';
5
+ export declare class SubtitlesHook implements IComponentHook {
6
+ #private;
7
+ types: HookType[];
8
+ priority: number;
9
+ private subtitlesManager;
10
+ private state;
11
+ constructor(cradle: {
12
+ subtitlesManager: SubtitlesManager;
13
+ stateManager: StateManager;
14
+ eventManager: EventManager;
15
+ });
16
+ get activeSubtitle(): {
17
+ id: string;
18
+ text: string;
19
+ start_at: number;
20
+ end_at: number;
21
+ visible?: boolean | undefined;
22
+ color?: string | {
23
+ type: "linear" | "radial";
24
+ colors: string[];
25
+ stops?: number[] | undefined;
26
+ angle?: number | undefined;
27
+ position?: string | undefined;
28
+ shape?: "ellipse" | "circle" | undefined;
29
+ } | undefined;
30
+ background?: string | {
31
+ type: "linear" | "radial";
32
+ colors: string[];
33
+ stops?: number[] | undefined;
34
+ angle?: number | undefined;
35
+ position?: string | undefined;
36
+ shape?: "ellipse" | "circle" | undefined;
37
+ } | undefined;
38
+ words?: [string, number, number, ...(import("zod").objectOutputType<{
39
+ s: import("zod").ZodOptional<import("zod").ZodNumber>;
40
+ si: import("zod").ZodOptional<import("zod").ZodNumber>;
41
+ c: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodEffects<import("zod").ZodString, string, string>, import("zod").ZodObject<{
42
+ type: import("zod").ZodEnum<["linear", "radial"]>;
43
+ colors: import("zod").ZodArray<import("zod").ZodEffects<import("zod").ZodString, string, string>, "many">;
44
+ stops: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodNumber, "many">>;
45
+ angle: import("zod").ZodOptional<import("zod").ZodNumber>;
46
+ position: import("zod").ZodOptional<import("zod").ZodString>;
47
+ shape: import("zod").ZodOptional<import("zod").ZodEnum<["ellipse", "circle"]>>;
48
+ }, "strip", import("zod").ZodTypeAny, {
49
+ type: "linear" | "radial";
50
+ colors: string[];
51
+ stops?: number[] | undefined;
52
+ angle?: number | undefined;
53
+ position?: string | undefined;
54
+ shape?: "ellipse" | "circle" | undefined;
55
+ }, {
56
+ type: "linear" | "radial";
57
+ colors: string[];
58
+ stops?: number[] | undefined;
59
+ angle?: number | undefined;
60
+ position?: string | undefined;
61
+ shape?: "ellipse" | "circle" | undefined;
62
+ }>]>>;
63
+ e: import("zod").ZodOptional<import("zod").ZodString>;
64
+ w: import("zod").ZodOptional<import("zod").ZodString>;
65
+ f: import("zod").ZodOptional<import("zod").ZodString>;
66
+ }, import("zod").ZodAny, "strip"> | null | undefined)[]][] | undefined;
67
+ emoji?: string | undefined;
68
+ enlarge?: number | undefined;
69
+ } | {
70
+ id: string;
71
+ text: string;
72
+ start_at: number;
73
+ end_at: number;
74
+ visible?: boolean | undefined;
75
+ color?: string | undefined;
76
+ background?: string | undefined;
77
+ words?: {
78
+ id: string;
79
+ text: string;
80
+ start_at: number;
81
+ end_at: number;
82
+ position?: number | undefined;
83
+ }[] | undefined;
84
+ emoji?: string | undefined;
85
+ enlarge?: number | undefined;
86
+ } | undefined;
87
+ handle(type: HookType, context: IComponentContext): Promise<void>;
88
+ }
@@ -0,0 +1,199 @@
1
+ import { gsap } from 'gsap';
2
+ import { get } from 'lodash-es';
3
+ export class SubtitlesHook {
4
+ #handlers = {
5
+ setup: this.#handleSetup.bind(this),
6
+ destroy: this.#handleDestroy.bind(this),
7
+ refresh: this.#handleRefresh.bind(this),
8
+ update: this.#handleUpdate.bind(this),
9
+ 'refresh:content': this.#handleRefresh.bind(this),
10
+ 'refresh:config': this.#handleRefresh.bind(this)
11
+ };
12
+ types = ['setup', 'update', 'destroy', 'refresh'];
13
+ priority = 1;
14
+ #context;
15
+ #initialized = false;
16
+ #subtitles = [];
17
+ #currentSubtitle = undefined;
18
+ #currentId = undefined;
19
+ #refreshed = false;
20
+ subtitlesManager;
21
+ state;
22
+ constructor(cradle) {
23
+ this.subtitlesManager = cradle.subtitlesManager;
24
+ this.state = cradle.stateManager;
25
+ cradle.eventManager.addEventListener('subtitlessettingschange', () => {
26
+ this.#refreshed = true;
27
+ });
28
+ }
29
+ #removePunctuation(text) {
30
+ if (this.subtitlesManager.settings.punctuation) {
31
+ // punctuation is enabled
32
+ return text;
33
+ }
34
+ // Remove common punctuation marks and chinese punctuation while preserving spaces and word structure
35
+ const regex = /[,.!,。!,]/g;
36
+ return text.replace(regex, '').trim();
37
+ }
38
+ async #handleSetup() {
39
+ if (this.#initialized) {
40
+ return;
41
+ }
42
+ this.#initialized = true;
43
+ const subtitles = this.subtitlesManager.data;
44
+ // Only SubtitleComponent has .source, so check type
45
+ const data = this.#context.data;
46
+ const source = data.source;
47
+ const assetId = data.source && typeof data.source.assetId === 'string' ? data.source.assetId : '';
48
+ if (!assetId) {
49
+ this.#buildFakeContext();
50
+ return;
51
+ }
52
+ const componentSubtitles = subtitles[assetId];
53
+ if (!componentSubtitles || Object.keys(componentSubtitles).length === 0) {
54
+ this.#buildFakeContext();
55
+ return;
56
+ }
57
+ // Extract subtitle array for the specific language or default
58
+ const assetSubtitles = this.subtitlesManager.getAssetSubtitles(assetId);
59
+ const languageCode = source?.languageCode || 'default';
60
+ const subtitleArray = assetSubtitles[languageCode] || Object.values(assetSubtitles)[0] || [];
61
+ this.#subtitles = subtitleArray;
62
+ // const el = this.#buildHtmlElement();
63
+ // this.#context.setResource('wrapperHtmlEl', el);
64
+ if (this.activeSubtitle === undefined) {
65
+ this.#buildFakeContext();
66
+ }
67
+ }
68
+ get activeSubtitle() {
69
+ if (this.#currentSubtitle) {
70
+ if (this.state.currentTime >= this.#currentSubtitle.start_at &&
71
+ this.state.currentTime <= this.#currentSubtitle.end_at) {
72
+ return this.#currentSubtitle.visible ? this.#currentSubtitle : undefined;
73
+ }
74
+ }
75
+ const subtitle = this.#subtitles.find((sub) => this.state.currentTime >= sub.start_at &&
76
+ this.state.currentTime <= sub.end_at &&
77
+ sub.visible !== false);
78
+ return subtitle;
79
+ }
80
+ #buildFakeContext() {
81
+ let background = this.#context.data.appearance.background;
82
+ if (typeof background === 'string') {
83
+ background = null;
84
+ }
85
+ const appearance = {
86
+ x: this.#context.data.appearance.x,
87
+ y: this.#context.data.appearance.y,
88
+ width: this.#context.data.appearance.width,
89
+ height: this.#context.data.appearance.height,
90
+ opacity: this.#context.data.appearance.opacity,
91
+ rotation: this.#context.data.appearance.rotation,
92
+ scaleX: this.#context.data.appearance.scaleX,
93
+ scaleY: this.#context.data.appearance.scaleY,
94
+ background,
95
+ backgroundAlwaysVisible: get(this.#context.data.appearance, 'backgroundAlwaysVisible', false)
96
+ };
97
+ const updateData = {
98
+ ...this.#context.data,
99
+ timeline: { startAt: -2, endAt: -1 },
100
+ appearance,
101
+ type: 'TEXT',
102
+ text: '',
103
+ animations: {
104
+ enabled: false,
105
+ list: []
106
+ }
107
+ };
108
+ this.#context.updateContextData(updateData);
109
+ }
110
+ async #handleUpdate() {
111
+ const contextId = this.activeSubtitle ? this.activeSubtitle.id : undefined;
112
+ if (contextId === this.#currentId && !this.#refreshed) {
113
+ return;
114
+ }
115
+ if ((this.activeSubtitle && this.activeSubtitle.id !== this.#context.contextData.id) ||
116
+ (this.activeSubtitle && this.#refreshed)) {
117
+ this.#currentId = this.activeSubtitle.id;
118
+ const startTime = this.activeSubtitle?.start_at ?? 0;
119
+ const endTime = this.activeSubtitle?.end_at ?? 0;
120
+ const duration = endTime - startTime;
121
+ const animationData = {};
122
+ const wordTimings = [];
123
+ this.activeSubtitle?.words?.forEach((word) => {
124
+ wordTimings.push(gsap.utils.clamp(0, duration, word[1] - startTime)); // timings is relative to the start of the subtitle
125
+ });
126
+ // reorder wordTimings by start_at
127
+ wordTimings.sort((a, b) => a - b);
128
+ animationData.wordStartTimes = wordTimings;
129
+ const wordUnhighlightTimes = [...wordTimings].slice(1);
130
+ if (wordUnhighlightTimes.length > 0) {
131
+ animationData.wordUnhighlightTimes = wordUnhighlightTimes;
132
+ }
133
+ animationData.lineStartTimes = [0, 1];
134
+ animationData.lineUnhighlightTimes = [1];
135
+ this.#context.setResource('animationData', animationData);
136
+ // we need to rebuild subtitle component as text component
137
+ const currentSize = get(this.#context.data, 'appearance.text.fontSize.value', get(this.#context.data, 'appearance.text.fontSize', 50));
138
+ const colorOverride = this.activeSubtitle.color ? { color: this.activeSubtitle.color } : {};
139
+ const visibleOverride = 'visible' in this.activeSubtitle ? { visible: this.activeSubtitle.visible } : {};
140
+ const fontSizeOverride = 'enlarge' in this.activeSubtitle && currentSize
141
+ ? {
142
+ fontSize: {
143
+ value: currentSize * (this.activeSubtitle.enlarge / 100),
144
+ unit: this.#context.data.appearance.text?.fontSize?.unit
145
+ }
146
+ }
147
+ : {};
148
+ const subtitleContextData = {
149
+ ...this.#context.data,
150
+ id: this.activeSubtitle.id,
151
+ type: 'TEXT',
152
+ text: this.#removePunctuation(this.activeSubtitle.text || ''),
153
+ timeline: {
154
+ startAt: this.activeSubtitle.start_at,
155
+ endAt: this.activeSubtitle.end_at
156
+ },
157
+ appearance: {
158
+ ...this.#context.data.appearance,
159
+ text: {
160
+ ...this.#context.data.appearance.text,
161
+ ...colorOverride,
162
+ ...fontSizeOverride
163
+ }
164
+ },
165
+ ...visibleOverride
166
+ };
167
+ this.#context.updateContextData(subtitleContextData);
168
+ if (this.#refreshed) {
169
+ this.#refreshed = false;
170
+ }
171
+ }
172
+ if (!this.activeSubtitle) {
173
+ this.#buildFakeContext();
174
+ }
175
+ }
176
+ async #handleRefresh() {
177
+ await this.#handleDestroy();
178
+ await this.#handleSetup();
179
+ this.#refreshed = true;
180
+ }
181
+ async #handleDestroy() {
182
+ const el = this.#context.getResource('wrapperHtmlEl');
183
+ if (el) {
184
+ el.remove();
185
+ this.#context.setResource('wrapperHtmlEl', undefined);
186
+ }
187
+ this.#subtitles = [];
188
+ this.#currentSubtitle = undefined;
189
+ this.#currentId = undefined;
190
+ this.#initialized = false;
191
+ }
192
+ async handle(type, context) {
193
+ this.#context = context;
194
+ const handler = this.#handlers[type];
195
+ if (handler) {
196
+ await handler();
197
+ }
198
+ }
199
+ }
@@ -0,0 +1,7 @@
1
+ import type { IComponentContext, IComponentHook, HookType } from '../..';
2
+ export declare class VerifyGifHook implements IComponentHook {
3
+ #private;
4
+ types: HookType[];
5
+ priority: number;
6
+ handle(type: HookType, context: IComponentContext): Promise<void>;
7
+ }
@@ -0,0 +1,27 @@
1
+ import { GifComponentShape } from '../..';
2
+ export class VerifyGifHook {
3
+ types = ['setup', 'refresh'];
4
+ priority = 1;
5
+ #context;
6
+ async #handleSetup() {
7
+ const data = GifComponentShape.safeParse(this.#context.contextData);
8
+ if (!data.success) {
9
+ console.error('GIF Compononent verify failed: ' + data.error.message);
10
+ this.#context.disabled = true;
11
+ return;
12
+ }
13
+ this.#context.setResource('gifShape', data.data);
14
+ }
15
+ async #handleRefresh() {
16
+ await this.#handleSetup();
17
+ }
18
+ async handle(type, context) {
19
+ this.#context = context;
20
+ if (type === 'setup') {
21
+ return await this.#handleSetup();
22
+ }
23
+ else if (type === 'refresh') {
24
+ return await this.#handleRefresh();
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,7 @@
1
+ import type { IComponentContext, IComponentHook, HookType } from '../..';
2
+ export declare class VerifyImageHook implements IComponentHook {
3
+ #private;
4
+ types: HookType[];
5
+ priority: number;
6
+ handle(type: HookType, context: IComponentContext): Promise<void>;
7
+ }
@@ -0,0 +1,27 @@
1
+ import { ImageComponentShape } from '../..';
2
+ export class VerifyImageHook {
3
+ types = ['setup', 'refresh'];
4
+ priority = 1;
5
+ #context;
6
+ async #handleSetup() {
7
+ const data = ImageComponentShape.safeParse(this.#context.contextData);
8
+ if (!data.success) {
9
+ console.error('Image Compononent verify failed: ' + data.error.message);
10
+ this.#context.disabled = true;
11
+ return;
12
+ }
13
+ this.#context.setResource('imageShape', data.data);
14
+ }
15
+ async #handleRefresh() {
16
+ await this.#handleSetup();
17
+ }
18
+ async handle(type, context) {
19
+ this.#context = context;
20
+ if (type === 'setup') {
21
+ return await this.#handleSetup();
22
+ }
23
+ else if (type === 'refresh') {
24
+ return await this.#handleRefresh();
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,7 @@
1
+ import type { IComponentContext, IComponentHook, HookType } from '../..';
2
+ export declare class VerifyMediaHook implements IComponentHook {
3
+ #private;
4
+ types: HookType[];
5
+ priority: number;
6
+ handle(type: HookType, context: IComponentContext): Promise<void>;
7
+ }