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,204 @@
1
+ import { z } from 'zod';
2
+ import { StateManager } from '../../managers/StateManager.svelte.js';
3
+ export class MediaSeekingHook {
4
+ types = ['setup', 'destroy', 'refresh', 'update'];
5
+ priority = 1;
6
+ #context;
7
+ #mediaElement;
8
+ state;
9
+ constructor(cradle) {
10
+ this.state = cradle.stateManager;
11
+ }
12
+ async #handleSetup() {
13
+ if (this.#mediaElement) {
14
+ return;
15
+ }
16
+ if (this.#context.contextData.type !== 'VIDEO' && this.#context.contextData.type !== 'AUDIO')
17
+ return;
18
+ const mediaType = this.#context.type === 'VIDEO' ? 'video' : 'audio';
19
+ const media = this.#context.getResource(mediaType === 'video' ? 'videoElement' : 'audioElement');
20
+ if (!media) {
21
+ console.error('MediaSeekingHook: No media element found');
22
+ return;
23
+ }
24
+ this.#mediaElement = media;
25
+ if (media && this.#context.isActive) {
26
+ const seekStatus = {
27
+ start: null,
28
+ end: null,
29
+ isSeeking: false
30
+ };
31
+ let canPlayTime = null;
32
+ let fullyReady = false;
33
+ let needCheckState = false;
34
+ const checkReadyState = async () => {
35
+ if (!needCheckState) {
36
+ return;
37
+ }
38
+ if (media.readyState < 3) {
39
+ await new Promise((resolve) => setTimeout(resolve, 500));
40
+ needCheckState = true;
41
+ return checkReadyState();
42
+ }
43
+ this.state.removeLoadingComponent(this.#context.contextData.id);
44
+ needCheckState = false;
45
+ if (media.readyState === 4) {
46
+ fullyReady = true;
47
+ }
48
+ };
49
+ media.onseeking = () => {
50
+ const mediaTime = parseFloat(media.currentTime.toFixed(1));
51
+ if (!seekStatus.isSeeking && seekStatus.start != mediaTime) {
52
+ seekStatus.start = mediaTime;
53
+ seekStatus.end = null;
54
+ seekStatus.isSeeking = true;
55
+ this.state.addLoadingComponent(this.#context.contextData.id, 'seeking');
56
+ needCheckState = true;
57
+ checkReadyState();
58
+ }
59
+ };
60
+ media.onseeked = () => {
61
+ const mediaTime = parseFloat(media.currentTime.toFixed(1));
62
+ if (seekStatus.isSeeking) {
63
+ seekStatus.end = mediaTime;
64
+ seekStatus.isSeeking = false;
65
+ if (media.readyState === 4) {
66
+ fullyReady = true;
67
+ }
68
+ needCheckState = false;
69
+ }
70
+ };
71
+ // Loading states
72
+ media.onwaiting = () => {
73
+ if (!fullyReady) {
74
+ this.state.addLoadingComponent(this.#context.contextData.id, 'waiting');
75
+ needCheckState = true;
76
+ checkReadyState();
77
+ }
78
+ };
79
+ media.oncanplay = () => {
80
+ const mediaTime = parseFloat(media.currentTime.toFixed(1));
81
+ if (canPlayTime != mediaTime) {
82
+ this.state.removeLoadingComponent(this.#context.contextData.id);
83
+ canPlayTime = mediaTime;
84
+ needCheckState = false;
85
+ }
86
+ if (media.readyState === 4) {
87
+ fullyReady = true;
88
+ }
89
+ // Don't try to play here - let MediaHook handle play/pause logic
90
+ // This prevents conflicts and race conditions, especially on Safari
91
+ };
92
+ // Add error event handling
93
+ media.onerror = () => {
94
+ console.error('Media error:', media.error);
95
+ };
96
+ }
97
+ }
98
+ async #handleRefresh() {
99
+ await this.#handleDestroy();
100
+ await this.#handleSetup();
101
+ }
102
+ async #handleDestroy() {
103
+ this.#mediaElement = undefined;
104
+ }
105
+ async #handleUpdate() {
106
+ // Only handle video components as requested
107
+ if (this.#context.contextData.type !== 'VIDEO')
108
+ return;
109
+ // Get the HTMLVideoElement from resources or cached reference
110
+ let media = this.#mediaElement;
111
+ if (!media) {
112
+ const res = this.#context.getResource('videoElement');
113
+ media = res;
114
+ this.#mediaElement = media; // cache for later
115
+ }
116
+ if (!media)
117
+ return;
118
+ const fps = this.state.data.settings.fps || 30;
119
+ const targetTime = this.#context.currentComponentTime;
120
+ const targetFrame = Math.round(targetTime * fps);
121
+ const currentFrame = Math.round(media.currentTime * fps);
122
+ const diff = Math.abs(currentFrame - targetFrame);
123
+ const needReseek = this.state.environment === 'server' ? currentFrame !== targetFrame : diff > 30;
124
+ if (this.state.environment !== 'server') {
125
+ if (!media.paused && this.state.state !== 'playing') {
126
+ media.pause();
127
+ }
128
+ }
129
+ if (needReseek) {
130
+ const seekTo = targetTime;
131
+ try {
132
+ // Prefer fastSeek when available for larger jumps
133
+ const largeJump = Math.abs(media.currentTime - seekTo) > 2 / fps;
134
+ if (typeof media.fastSeek === 'function' && largeJump) {
135
+ media.fastSeek(seekTo);
136
+ }
137
+ else {
138
+ media.currentTime = seekTo;
139
+ }
140
+ // Await seek completion using a robust multi-attempt strategy similar to Remotion
141
+ await new Promise((resolve) => {
142
+ const anyMedia = media;
143
+ let attempts = 0;
144
+ const maxAttempts = 8;
145
+ const check = () => {
146
+ const fps = this.state.data.settings.fps || 30;
147
+ const desiredFrame = Math.round(seekTo * fps);
148
+ const currFrame = Math.round(media.currentTime * fps);
149
+ if (desiredFrame === currFrame && media.readyState >= 2) {
150
+ return resolve();
151
+ }
152
+ attempts++;
153
+ if (attempts >= maxAttempts)
154
+ return resolve();
155
+ setTimeout(check, 20);
156
+ };
157
+ if (typeof anyMedia.requestVideoFrameCallback === 'function') {
158
+ const timeout = setTimeout(check, 120);
159
+ anyMedia.requestVideoFrameCallback(() => {
160
+ clearTimeout(timeout);
161
+ check();
162
+ });
163
+ }
164
+ else {
165
+ media.addEventListener('seeked', check, { once: true });
166
+ setTimeout(check, 60);
167
+ }
168
+ });
169
+ // Force Pixi video texture to pull the updated frame if present
170
+ try {
171
+ const tex = this.#context.getResource('pixiTexture');
172
+ const baseTex = tex?.baseTexture;
173
+ if (baseTex?.resource && typeof baseTex.resource.update === 'function') {
174
+ baseTex.resource.update();
175
+ }
176
+ else if (typeof baseTex?.update === 'function') {
177
+ baseTex.update();
178
+ }
179
+ }
180
+ catch { }
181
+ }
182
+ catch (err) {
183
+ // Swallow errors here; next update tick will retry if needed
184
+ }
185
+ }
186
+ }
187
+ async handle(type, context) {
188
+ this.#context = context;
189
+ if (this.#context.contextData.type !== 'VIDEO' && this.#context.contextData.type !== 'AUDIO')
190
+ return;
191
+ if (type === 'setup') {
192
+ return await this.#handleSetup();
193
+ }
194
+ else if (type === 'destroy') {
195
+ return await this.#handleDestroy();
196
+ }
197
+ else if (type === 'refresh') {
198
+ return await this.#handleRefresh();
199
+ }
200
+ else if (type === 'update') {
201
+ return await this.#handleUpdate();
202
+ }
203
+ }
204
+ }
@@ -0,0 +1,15 @@
1
+ import type { IComponentContext, IComponentHook, HookType } from '../..';
2
+ import { StateManager } from '../../managers/StateManager.svelte.js';
3
+ export declare class PixiDisplayObjectHook implements IComponentHook {
4
+ #private;
5
+ types: HookType[];
6
+ priority: number;
7
+ private state;
8
+ constructor(cradle: {
9
+ stateManager: StateManager;
10
+ });
11
+ get sceneWidth(): number;
12
+ get sceneHeight(): number;
13
+ private initMainSprite;
14
+ handle(type: HookType, context: IComponentContext): Promise<void>;
15
+ }
@@ -0,0 +1,77 @@
1
+ import * as PIXI from 'pixi.js-legacy';
2
+ import { setPlacementAndOpacity } from '../../utils/utils.js';
3
+ import { StateManager } from '../../managers/StateManager.svelte.js';
4
+ export class PixiDisplayObjectHook {
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
+ };
12
+ priority = 1;
13
+ #context;
14
+ #pixiTexture;
15
+ #displayObject;
16
+ state;
17
+ constructor(cradle) {
18
+ this.state = cradle.stateManager;
19
+ }
20
+ get sceneWidth() {
21
+ return this.#context.sceneState.width;
22
+ }
23
+ get sceneHeight() {
24
+ return this.#context.sceneState.height;
25
+ }
26
+ initMainSprite() {
27
+ const sprite = new PIXI.Sprite(this.#pixiTexture);
28
+ setPlacementAndOpacity(sprite, this.#context.data.appearance);
29
+ this.#displayObject.addChild(sprite);
30
+ }
31
+ #initDisplayObject() {
32
+ this.initMainSprite();
33
+ }
34
+ async #handleRefresh() {
35
+ await this.#handleDestroy();
36
+ this.#initDisplayObject();
37
+ await this.#handleUpdate();
38
+ }
39
+ async #handleUpdate() {
40
+ const isActive = this.#context.isActive;
41
+ if (this.#displayObject) {
42
+ // Only mark dirty if visibility actually changed
43
+ if (this.#displayObject.visible !== isActive) {
44
+ this.#displayObject.visible = isActive;
45
+ // Mark scene as dirty when visibility changes
46
+ this.state.markDirty();
47
+ }
48
+ return;
49
+ }
50
+ // Check if this is a progress shape (which creates pixiRenderObject directly)
51
+ const existingRenderObject = this.#context.getResource('pixiRenderObject');
52
+ if (existingRenderObject) {
53
+ // Progress shapes already have their display object set up
54
+ this.#displayObject = existingRenderObject;
55
+ return;
56
+ }
57
+ // Regular shapes need texture to create sprite
58
+ const texture = this.#context.getResource('pixiTexture');
59
+ if (!texture) {
60
+ throw new Error('pixiTexture not found in resources.');
61
+ }
62
+ this.#pixiTexture = texture;
63
+ this.#displayObject = new PIXI.Container();
64
+ this.#initDisplayObject();
65
+ this.#context.setResource('pixiRenderObject', this.#displayObject);
66
+ }
67
+ async #handleDestroy() {
68
+ this.#displayObject.removeChildren();
69
+ }
70
+ async handle(type, context) {
71
+ this.#context = context;
72
+ const handler = this.#handlers[type];
73
+ if (handler) {
74
+ await handler();
75
+ }
76
+ }
77
+ }
@@ -0,0 +1,15 @@
1
+ import type { IComponentContext, IComponentHook, HookType } from '../..';
2
+ import { GifComponentShape } from '../..';
3
+ import { z } from 'zod';
4
+ import type { StateManager } from '../../managers/StateManager.svelte.ts';
5
+ export declare class PixiGifHook implements IComponentHook {
6
+ #private;
7
+ types: HookType[];
8
+ priority: number;
9
+ componentElement: z.infer<typeof GifComponentShape>;
10
+ private state;
11
+ constructor(cradle: {
12
+ stateManager: StateManager;
13
+ });
14
+ handle(type: HookType, context: IComponentContext): Promise<void>;
15
+ }
@@ -0,0 +1,97 @@
1
+ import { GifComponentShape } from '../..';
2
+ import { z } from 'zod';
3
+ import { AnimatedGIF } from '../AnimatedGIF.js';
4
+ import { Container } from 'pixi.js-legacy';
5
+ import { setPlacementAndOpacity } from '../../utils/utils.js';
6
+ export class PixiGifHook {
7
+ types = ['setup', 'update', 'destroy', 'refresh'];
8
+ priority = 1;
9
+ #context;
10
+ #imageElement;
11
+ #displayObject;
12
+ componentElement;
13
+ state;
14
+ #destroyed = false;
15
+ #previousUrlLoaded = '';
16
+ constructor(cradle) {
17
+ this.state = cradle.stateManager;
18
+ }
19
+ async #handleSetup() {
20
+ if (this.#imageElement && !this.#destroyed) {
21
+ return;
22
+ }
23
+ // use cached imageElement if url did not change
24
+ if (this.#previousUrlLoaded !== this.componentElement.source.url) {
25
+ const res = await fetch(this.componentElement.source.url);
26
+ const ab = await res.arrayBuffer();
27
+ const img = AnimatedGIF.fromBuffer(ab);
28
+ if (img) {
29
+ this.#displayObject = this.#displayObject || new Container();
30
+ this.#imageElement = img;
31
+ this.#previousUrlLoaded = this.componentElement.source.url;
32
+ }
33
+ }
34
+ if (this.#imageElement) {
35
+ const { appearance } = this.componentElement;
36
+ setPlacementAndOpacity(this.#imageElement, appearance);
37
+ this.#displayObject.addChild(this.#imageElement);
38
+ this.#context.setResource('pixiRenderObject', this.#displayObject);
39
+ this.#imageElement.play();
40
+ // await new promise 100ms timeout
41
+ await new Promise((resolve) => setTimeout(resolve, 100));
42
+ }
43
+ this.#destroyed = false;
44
+ }
45
+ async #handleRefresh() {
46
+ await this.#handleDestroy();
47
+ await this.#handleSetup();
48
+ await this.#handleUpdate();
49
+ }
50
+ async #handleDestroy() {
51
+ this.#destroyed = true;
52
+ if (this.#displayObject)
53
+ this.#displayObject.removeChildren();
54
+ }
55
+ async #handleUpdate() {
56
+ if (!this.#imageElement || this.#destroyed) {
57
+ return;
58
+ }
59
+ if (this.state.isPlaying) {
60
+ this.#imageElement.play();
61
+ }
62
+ else {
63
+ this.#imageElement.stop();
64
+ const gifFrame = this.#imageElement.totalFrames > 0
65
+ ? this.state.currentFrame % this.#imageElement.totalFrames
66
+ : 0;
67
+ this.#imageElement.currentFrame = gifFrame;
68
+ }
69
+ const isActive = this.#context.isActive;
70
+ if (this.#displayObject) {
71
+ if (this.#displayObject.visible != isActive) {
72
+ this.#displayObject.visible = isActive;
73
+ }
74
+ if (!isActive) {
75
+ this.#imageElement.stop();
76
+ }
77
+ }
78
+ }
79
+ async handle(type, context) {
80
+ this.#context = context;
81
+ const data = this.#context.contextData;
82
+ if (!data || data.type !== 'GIF') {
83
+ return;
84
+ }
85
+ this.componentElement = data;
86
+ if (type === 'setup') {
87
+ return await this.#handleSetup();
88
+ }
89
+ else if (type === 'destroy') {
90
+ return await this.#handleDestroy();
91
+ }
92
+ else if (type === 'refresh') {
93
+ return await this.#handleRefresh();
94
+ }
95
+ await this.#handleUpdate();
96
+ }
97
+ }
@@ -0,0 +1,12 @@
1
+ import type { IComponentContext, IComponentHook, HookType } from '../..';
2
+ import { StateManager } from '../../managers/StateManager.svelte.js';
3
+ export declare class PixiProgressShapeHook implements IComponentHook {
4
+ #private;
5
+ types: HookType[];
6
+ priority: number;
7
+ private state;
8
+ constructor(cradle: {
9
+ stateManager: StateManager;
10
+ });
11
+ handle(type: HookType, context: IComponentContext): Promise<void>;
12
+ }
@@ -0,0 +1,128 @@
1
+ import * as PIXI from 'pixi.js-legacy';
2
+ import { setPlacementAndOpacity } from '../../utils/utils.js';
3
+ import { StateManager } from '../../managers/StateManager.svelte.js';
4
+ import { ProgressRenderer, LinearProgressRenderer, RadialProgressRenderer, PerimeterProgressRenderer, DoubleProgressRenderer, CustomProgressRenderer } from './shapes/progress/index.js';
5
+ class ProgressRendererFactory {
6
+ static create(context, width, height, config) {
7
+ const type = config.type;
8
+ switch (config.type) {
9
+ case 'linear':
10
+ return new LinearProgressRenderer(context, width, height, config);
11
+ case 'radial':
12
+ return new RadialProgressRenderer(context, width, height, config);
13
+ case 'perimeter':
14
+ return new PerimeterProgressRenderer(context, width, height, config);
15
+ case 'double':
16
+ return new DoubleProgressRenderer(context, width, height, config);
17
+ case 'custom':
18
+ return new CustomProgressRenderer(context, width, height, config);
19
+ default:
20
+ throw new Error(`Unsupported progress type: ${type}`);
21
+ }
22
+ }
23
+ }
24
+ export class PixiProgressShapeHook {
25
+ types = ['setup', 'update', 'destroy', 'refresh'];
26
+ priority = 1;
27
+ #context;
28
+ #renderer;
29
+ #lastProgress = -1;
30
+ state;
31
+ constructor(cradle) {
32
+ this.state = cradle.stateManager;
33
+ }
34
+ #handlers = {
35
+ setup: this.#handleSetup.bind(this),
36
+ update: this.#handleUpdate.bind(this),
37
+ refresh: this.#handleRefresh.bind(this),
38
+ destroy: this.#handleDestroy.bind(this)
39
+ };
40
+ async #handleSetup(force = false) {
41
+ if (this.#context.data.type !== 'SHAPE')
42
+ return;
43
+ if (this.#renderer && !force)
44
+ return;
45
+ const shapeData = this.#context.data;
46
+ if (shapeData.shape.type !== 'progress')
47
+ return;
48
+ const { width, height } = shapeData.appearance;
49
+ const progressConfig = shapeData.shape.progressConfig || {
50
+ type: 'linear',
51
+ direction: 'horizontal',
52
+ reverse: false,
53
+ anchor: 'start'
54
+ };
55
+ this.#renderer = ProgressRendererFactory.create(this.#context, width, height, progressConfig);
56
+ const displayObject = this.#renderer.getDisplayObject();
57
+ this.#context.setResource('pixiRenderObject', displayObject);
58
+ setPlacementAndOpacity(displayObject, shapeData.appearance);
59
+ this.#renderer.update(this.#context.progress);
60
+ }
61
+ async #handleRefresh() {
62
+ // Preserve parent and index so the new display object is re-attached
63
+ const oldDisplayObject = this.#renderer?.getDisplayObject();
64
+ const parent = oldDisplayObject?.parent;
65
+ const index = parent && oldDisplayObject ? parent.getChildIndex(oldDisplayObject) : -1;
66
+ await this.#handleDestroy();
67
+ await this.#handleSetup(true);
68
+ // Re-attach new display object to the same parent/index
69
+ if (parent && this.#renderer) {
70
+ const newDisplayObject = this.#renderer.getDisplayObject();
71
+ if (index >= 0 && index <= parent.children.length) {
72
+ parent.addChildAt(newDisplayObject, index);
73
+ }
74
+ else {
75
+ parent.addChild(newDisplayObject);
76
+ }
77
+ }
78
+ }
79
+ async #handleUpdate() {
80
+ if (!this.#renderer) {
81
+ await this.#handleSetup();
82
+ return;
83
+ }
84
+ if (this.#context.data.type !== 'SHAPE')
85
+ return;
86
+ const shapeData = this.#context.data;
87
+ if (shapeData.shape.type !== 'progress')
88
+ return;
89
+ const displayObject = this.#renderer.getDisplayObject();
90
+ const isActive = this.#context.isActive;
91
+ if (displayObject.visible !== isActive) {
92
+ displayObject.visible = isActive;
93
+ this.state.markDirty();
94
+ }
95
+ setPlacementAndOpacity(displayObject, shapeData.appearance);
96
+ const currentProgress = this.#context.progress;
97
+ if (this.#lastProgress !== currentProgress) {
98
+ this.#renderer.update(currentProgress);
99
+ this.#lastProgress = currentProgress;
100
+ // Mark dirty only if progress actually changed
101
+ this.state.markDirty();
102
+ }
103
+ }
104
+ async #handleDestroy() {
105
+ if (this.#renderer) {
106
+ const displayObject = this.#renderer.getDisplayObject();
107
+ // Detach from parent before destroying to avoid dangling references in the layer
108
+ if (displayObject.parent) {
109
+ displayObject.parent.removeChild(displayObject);
110
+ }
111
+ displayObject.destroy();
112
+ this.#renderer = undefined;
113
+ // Remove stale resource pointer
114
+ this.#context.removeResource('pixiRenderObject');
115
+ }
116
+ }
117
+ async handle(type, context) {
118
+ this.#context = context;
119
+ if (this.#context.data.type !== 'SHAPE')
120
+ return;
121
+ const shapeData = this.#context.data;
122
+ if (shapeData.shape.type !== 'progress')
123
+ return;
124
+ const handler = this.#handlers[type];
125
+ if (handler)
126
+ await handler();
127
+ }
128
+ }
@@ -0,0 +1,21 @@
1
+ import type { IComponentContext, IComponentHook, HookType } from '../..';
2
+ import { VideoComponentShape } from '../..';
3
+ import { z } from 'zod';
4
+ import type { StateManager } from '../../managers/StateManager.svelte.ts';
5
+ export declare class PixiSplitScreenDisplayObjectHook implements IComponentHook {
6
+ #private;
7
+ types: HookType[];
8
+ priority: number;
9
+ componentElement: z.infer<typeof VideoComponentShape>;
10
+ private sceneState;
11
+ constructor(cradle: {
12
+ stateManager: StateManager;
13
+ });
14
+ get sceneWidth(): number;
15
+ get sceneHeight(): number;
16
+ private initBlurBackground;
17
+ private setupBackground;
18
+ private initSplitScreen;
19
+ private initMainSprite;
20
+ handle(type: HookType, context: IComponentContext): Promise<void>;
21
+ }