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,125 @@
1
+ import { ComponentsManager } from '../managers/ComponentsManager.svelte.js';
2
+ import { EventManager } from '../managers/EventManager.js';
3
+ import { Container } from 'pixi.js-legacy';
4
+ import md5 from 'md5';
5
+ export class Layer {
6
+ #id;
7
+ #componentsInitData = [];
8
+ #isBuilt = false;
9
+ #displayObject;
10
+ components;
11
+ name;
12
+ order;
13
+ visible;
14
+ componentsManager;
15
+ eventManager;
16
+ constructor(cradle) {
17
+ const name = $state(cradle.layerData.name);
18
+ const order = $state(cradle.layerData.order);
19
+ const visible = $state(cradle.layerData.visible === false ? false : true);
20
+ const components = $state([]);
21
+ this.#id = cradle.layerData.id;
22
+ this.name = name ?? 'Layer';
23
+ this.order = order;
24
+ this.visible = visible;
25
+ this.#componentsInitData = cradle.layerData.components;
26
+ this.components = components;
27
+ this.componentsManager = cradle.componentsManager;
28
+ this.eventManager = cradle.eventManager;
29
+ }
30
+ async build() {
31
+ if (this.#isBuilt) {
32
+ return;
33
+ }
34
+ this.#isBuilt = true;
35
+ this.#displayObject = new Container();
36
+ for (const componentData of this.#componentsInitData) {
37
+ const component = await this.componentsManager.create(componentData);
38
+ if (component) {
39
+ this.addComponent(component);
40
+ }
41
+ }
42
+ }
43
+ #emit(event, props) {
44
+ this.eventManager.emit(event, props);
45
+ }
46
+ addComponent(component) {
47
+ this.components.push(component);
48
+ if (component.displayObject) {
49
+ this.#displayObject.addChild(component.displayObject);
50
+ }
51
+ // resort components
52
+ this.components.sort((a, b) => a.props.timeline.startAt - b.props.timeline.startAt);
53
+ this.#emit('layerschange');
54
+ }
55
+ removeComponent(component) {
56
+ const hasComponent = this.components.find((c) => c.id === component.id);
57
+ if (hasComponent) {
58
+ this.components = this.components.filter((c) => c.id !== component.id);
59
+ if (component.displayObject) {
60
+ this.#displayObject.removeChild(component.displayObject);
61
+ }
62
+ this.components.sort((a, b) => a.props.timeline.startAt - b.props.timeline.startAt);
63
+ this.#emit('layerschange');
64
+ }
65
+ }
66
+ update(props) {
67
+ let changed = false;
68
+ if (props.name) {
69
+ this.name = props.name;
70
+ changed = true;
71
+ }
72
+ if (props.order) {
73
+ this.order = props.order;
74
+ changed = true;
75
+ }
76
+ if (props.visible) {
77
+ this.visible = props.visible;
78
+ changed = true;
79
+ }
80
+ if (changed) {
81
+ this.#emit('layerschange');
82
+ }
83
+ }
84
+ setOrder(order) {
85
+ this.order = order;
86
+ this.#displayObject.zIndex = order;
87
+ this.#emit('layerschange');
88
+ }
89
+ getData() {
90
+ return {
91
+ id: this.id,
92
+ name: this.name,
93
+ // checksum: this.checksum,
94
+ order: this.order,
95
+ components: this.components.map((comp) => comp.props.getData()),
96
+ visible: this.visible,
97
+ muted: false
98
+ };
99
+ }
100
+ destroy() {
101
+ if (this.#displayObject) {
102
+ for (const component of this.components) {
103
+ component.destroy();
104
+ }
105
+ this.#displayObject.destroy();
106
+ }
107
+ }
108
+ get displayObject() {
109
+ return this.#displayObject;
110
+ }
111
+ get id() {
112
+ return this.#id;
113
+ }
114
+ get checksum() {
115
+ const checksums = this.components.map((comp) => comp.checksum);
116
+ const checksum = md5(this.order + checksums.join(','));
117
+ return this.id + '-' + checksum; // TODO generate checksum
118
+ }
119
+ get type() {
120
+ if (this.components.length) {
121
+ return this.components[0].type;
122
+ }
123
+ return undefined;
124
+ }
125
+ }
@@ -0,0 +1,23 @@
1
+ import * as PIXI from 'pixi.js-legacy';
2
+ import { DomManager } from './DomManager.js';
3
+ import { StateManager } from './StateManager.svelte.js';
4
+ export declare class AppManager {
5
+ #private;
6
+ private state;
7
+ private dom;
8
+ private forceCanvas;
9
+ constructor(cradle: {
10
+ stateManager: StateManager;
11
+ domManager: DomManager;
12
+ forceCanvas: boolean;
13
+ });
14
+ get app(): PIXI.Application;
15
+ get stage(): PIXI.Container;
16
+ get screen(): PIXI.Rectangle;
17
+ initialize(): Promise<void>;
18
+ extractBase64(target?: PIXI.DisplayObject | PIXI.RenderTexture, format?: string, quality?: number): Promise<string>;
19
+ resize(width: number, height: number): void;
20
+ render(): void;
21
+ scale(scale: number): void;
22
+ destroy(): void;
23
+ }
@@ -0,0 +1,89 @@
1
+ import * as PIXI from 'pixi.js-legacy';
2
+ import { PIXI_DEFAULTS } from '../constants.js';
3
+ import { registerGsapPlugins } from '../registers.js';
4
+ import { DomManager } from './DomManager.js';
5
+ import { StateManager } from './StateManager.svelte.js';
6
+ export class AppManager {
7
+ #app;
8
+ #destroyed = false;
9
+ state;
10
+ dom;
11
+ forceCanvas; // ForceCanvas
12
+ constructor(cradle) {
13
+ this.state = cradle.stateManager;
14
+ this.dom = cradle.domManager;
15
+ this.forceCanvas = cradle.forceCanvas;
16
+ }
17
+ get app() {
18
+ return this.#app;
19
+ }
20
+ get stage() {
21
+ return this.#app.stage;
22
+ }
23
+ get screen() {
24
+ return this.#app.screen;
25
+ }
26
+ async initialize() {
27
+ if (this.#app && !this.#destroyed) {
28
+ return;
29
+ }
30
+ const { width, height, environment, scale } = this.state;
31
+ this.#destroyed = false;
32
+ const canvas = this.dom.canvas;
33
+ if (environment === 'server') {
34
+ const ctx = canvas.getContext('2d', { willReadFrequently: true });
35
+ }
36
+ const { PixiPlugin } = await registerGsapPlugins();
37
+ // give the plugin a reference to the PIXI object
38
+ PixiPlugin.registerPIXI(this.app);
39
+ const options = {
40
+ ...PIXI_DEFAULTS,
41
+ preserveDrawingBuffer: environment === 'server',
42
+ // clearBeforeRender: environment === 'server' ? false : true,
43
+ width,
44
+ height,
45
+ view: canvas,
46
+ forceCanvas: environment === 'server' || this.forceCanvas,
47
+ backgroundColor: environment === 'server' ? 'transparent' : '#ffffff',
48
+ backgroundAlpha: environment === 'server' ? 0 : 1
49
+ };
50
+ this.#app = new PIXI.Application(options);
51
+ if (scale !== 1) {
52
+ this.scale(scale);
53
+ }
54
+ // Stop the default ticker as we'll use GSAP's ticker
55
+ this.#app.ticker.stop();
56
+ }
57
+ async extractBase64(target, format = 'png', quality = 1) {
58
+ if (!this.#app)
59
+ throw new Error('App not initialized');
60
+ if ('extract' in this.#app.renderer) {
61
+ return this.#app.renderer.extract.base64(target, format, quality);
62
+ }
63
+ throw new Error('Extract not supported in current renderer');
64
+ }
65
+ resize(width, height) {
66
+ this.#app.renderer.resize(width, height);
67
+ }
68
+ render() {
69
+ if (!this.#app)
70
+ return;
71
+ this.#app.render();
72
+ }
73
+ scale(scale) {
74
+ if (!this.#app)
75
+ throw new Error('App not initialized');
76
+ this.#app.stage.scale.set(scale);
77
+ this.#app.render();
78
+ }
79
+ destroy() {
80
+ if (this.#app) {
81
+ this.#app.destroy(true, {
82
+ children: true,
83
+ texture: true,
84
+ baseTexture: true
85
+ });
86
+ this.#destroyed = true;
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,49 @@
1
+ import { StateManager } from './StateManager.svelte.js';
2
+ import { EventManager } from './EventManager.js';
3
+ import type { MediaComponent, ResourceManager, IComponent, ComponentData, ComponentRefreshType } from '..';
4
+ import type { AppearanceInput } from '..';
5
+ import { Component } from '../components/Component.svelte.js';
6
+ import { type AwilixContainer } from 'awilix/browser';
7
+ import type { LayersManager } from './LayersManager.svelte.js';
8
+ export declare class ComponentsManager implements ResourceManager<IComponent, ComponentData, AppearanceInput> {
9
+ #private;
10
+ private components;
11
+ private isBuilding;
12
+ private state;
13
+ private eventManager;
14
+ private layersManager;
15
+ private container;
16
+ private debouncedRefreshSubtitles;
17
+ constructor(cradle: {
18
+ stateManager: StateManager;
19
+ eventManager: EventManager;
20
+ layersManager: LayersManager;
21
+ container: AwilixContainer;
22
+ });
23
+ private initializeEventListeners;
24
+ private isVisible;
25
+ getAll(): IComponent[];
26
+ getMediaComponents(): (Component & MediaComponent)[];
27
+ update(componentId: string, data: Partial<AppearanceInput>, refreshType?: ComponentRefreshType): Promise<void>;
28
+ get(componentId: string): IComponent | undefined;
29
+ delete(componentId: string): void;
30
+ create(componentData: ComponentData): Promise<IComponent | null>;
31
+ setOrder(id: string, order: number): void;
32
+ moveUp(id: string): void;
33
+ moveDown(id: string): void;
34
+ moveToTop(id: string): void;
35
+ moveToBottom(id: string): void;
36
+ moveAfter(id: string, targetId: string): void;
37
+ moveBefore(id: string, targetId: string): void;
38
+ bulkUpdate(updates: {
39
+ id: string;
40
+ data: Partial<AppearanceInput>;
41
+ }[]): void;
42
+ bulkDelete(ids: string[]): void;
43
+ hide(id: string): Promise<void>;
44
+ show(id: string): Promise<void>;
45
+ toggle(id: string): Promise<void>;
46
+ filter(predicate: (component: IComponent) => boolean): IComponent[];
47
+ isComponentVisible(componentId: string): boolean;
48
+ destroy(): void;
49
+ }
@@ -0,0 +1,247 @@
1
+ import { StateManager } from './StateManager.svelte.js';
2
+ import { EventManager } from './EventManager.js';
3
+ import { Component } from '../components/Component.svelte.js';
4
+ import { ComponentDirector } from '../directors/ComponentDirector.js';
5
+ import { PixiComponentBuilder } from '../builders/PixiComponentBuilder.js';
6
+ import { ComponentState } from '../builders/_ComponentState.svelte.js';
7
+ import { asClass, asValue } from 'awilix/browser';
8
+ import { debounce } from 'lodash-es';
9
+ // import { builtTextComponentForSubtitle } from '../utils/subtitles.js';
10
+ export class ComponentsManager {
11
+ components = $state(new Map());
12
+ isBuilding = false;
13
+ state;
14
+ eventManager;
15
+ layersManager;
16
+ container;
17
+ debouncedRefreshSubtitles;
18
+ constructor(cradle) {
19
+ this.state = cradle.stateManager;
20
+ this.eventManager = cradle.eventManager;
21
+ this.layersManager = cradle.layersManager;
22
+ this.container = cradle.container;
23
+ // Debounce subtitle refreshes to batch rapid changes (16ms = ~60fps)
24
+ this.debouncedRefreshSubtitles = debounce(() => this.#scheduleSubtitleRefresh(), 16, {
25
+ leading: false,
26
+ trailing: true
27
+ });
28
+ this.initializeEventListeners();
29
+ }
30
+ initializeEventListeners() {
31
+ this.eventManager.on('subtitleschange', this.debouncedRefreshSubtitles.bind(this));
32
+ }
33
+ #scheduleSubtitleRefresh() {
34
+ // Schedule the refresh on the next animation frame to avoid blocking
35
+ requestAnimationFrame(() => {
36
+ const components = this.filter((c) => c.type === 'SUBTITLES');
37
+ components.forEach((c) => {
38
+ c.refresh();
39
+ });
40
+ });
41
+ }
42
+ isVisible(component) {
43
+ const { currentTime, duration } = this.state;
44
+ const startAt = component.props.timeline.startAt || 0;
45
+ const endAt = component.props.timeline.endAt || duration;
46
+ return currentTime >= startAt && currentTime <= endAt;
47
+ }
48
+ getAll() {
49
+ return Array.from(this.components.values());
50
+ }
51
+ getMediaComponents() {
52
+ return this.getAll().filter((component) => ['VIDEO', 'AUDIO'].includes(component.type));
53
+ }
54
+ #refreshComponent(component, refreshType = 'refresh') {
55
+ component.refresh();
56
+ if (refreshType != 'refresh') {
57
+ component.refresh(refreshType);
58
+ }
59
+ }
60
+ async update(componentId, data, refreshType = 'refresh') {
61
+ const component = this.get(componentId);
62
+ if (component) {
63
+ await component.props.updateAppearance(data);
64
+ // Only manually refresh if auto-refresh is not enabled
65
+ if (!component.autoRefresh) {
66
+ this.#refreshComponent(component, refreshType);
67
+ }
68
+ }
69
+ }
70
+ get(componentId) {
71
+ return this.components.get(componentId);
72
+ }
73
+ delete(componentId) {
74
+ const component = this.components.get(componentId);
75
+ if (component) {
76
+ const layers = this.layersManager.getAll();
77
+ const componentLayer = layers.find((layer) => layer.components.some((component) => component.id === componentId));
78
+ // manage parent layer
79
+ if (componentLayer) {
80
+ componentLayer.removeComponent(component);
81
+ if (!componentLayer.components.length) {
82
+ this.layersManager.delete(componentLayer.id);
83
+ }
84
+ }
85
+ component.destroy();
86
+ this.components.delete(componentId);
87
+ }
88
+ }
89
+ async #buildComponent(componentData) {
90
+ // this.container.registerInstance('ComponentData', componentData);
91
+ // const director = this.container.resolve(ComponentDirector);
92
+ // const builder = this.container.resolve(PixiComponentBuilder);
93
+ const componentScope = this.container.createScope();
94
+ // Register component-specific data in the scope
95
+ componentScope.register({
96
+ componentData: asValue(componentData),
97
+ componentState: asClass(ComponentState)
98
+ });
99
+ const director = componentScope.resolve('componentDirector');
100
+ const builder = componentScope.resolve('pixiComponentBuilder');
101
+ director.setBuilder(builder);
102
+ director.setComponentData(componentData);
103
+ const component = director.constructAuto();
104
+ await component.setup();
105
+ await component.update();
106
+ return component;
107
+ }
108
+ async create(componentData) {
109
+ if (this.isBuilding) {
110
+ throw new Error('Attempted to create multiple components simultaneously. Construct one at the time.');
111
+ }
112
+ this.isBuilding = true;
113
+ let component = null;
114
+ try {
115
+ component = await this.#buildComponent(componentData);
116
+ this.components.set(componentData.id, component);
117
+ }
118
+ catch (err) {
119
+ console.error(err);
120
+ }
121
+ finally {
122
+ this.isBuilding = false;
123
+ }
124
+ return component;
125
+ }
126
+ setOrder(id, order) {
127
+ this.#reorderComponent(id, (components, index) => {
128
+ const [component] = components.splice(index, 1);
129
+ components.splice(order, 0, component);
130
+ });
131
+ }
132
+ moveUp(id) {
133
+ this.#reorderComponent(id, (components, index) => {
134
+ if (index <= 0)
135
+ return false;
136
+ [components[index - 1], components[index]] = [components[index], components[index - 1]];
137
+ });
138
+ }
139
+ moveDown(id) {
140
+ this.#reorderComponent(id, (components, index) => {
141
+ if (index >= components.length - 1)
142
+ return false;
143
+ [components[index], components[index + 1]] = [components[index + 1], components[index]];
144
+ });
145
+ }
146
+ moveToTop(id) {
147
+ this.#reorderComponent(id, (components, index) => {
148
+ if (index === 0)
149
+ return false;
150
+ const [component] = components.splice(index, 1);
151
+ components.unshift(component);
152
+ });
153
+ }
154
+ moveToBottom(id) {
155
+ this.#reorderComponent(id, (components, index) => {
156
+ if (index === components.length - 1)
157
+ return false;
158
+ const [component] = components.splice(index, 1);
159
+ components.push(component);
160
+ });
161
+ }
162
+ moveAfter(id, targetId) {
163
+ this.#reorderComponent(id, (components, index) => {
164
+ const targetIndex = components.findIndex((c) => c.id === targetId);
165
+ if (targetIndex === -1)
166
+ return false;
167
+ const [component] = components.splice(index, 1);
168
+ const newTargetIndex = components.findIndex((c) => c.id === targetId);
169
+ components.splice(newTargetIndex + 1, 0, component);
170
+ });
171
+ }
172
+ moveBefore(id, targetId) {
173
+ this.#reorderComponent(id, (components, index) => {
174
+ const targetIndex = components.findIndex((c) => c.id === targetId);
175
+ if (targetIndex === -1)
176
+ return false;
177
+ const [component] = components.splice(index, 1);
178
+ const newTargetIndex = components.findIndex((c) => c.id === targetId);
179
+ components.splice(newTargetIndex, 0, component);
180
+ });
181
+ }
182
+ #reorderComponent(id, reorderFn) {
183
+ const layer = this.#findLayerByComponentId(id);
184
+ if (!layer)
185
+ return;
186
+ const index = layer.components.findIndex((c) => c.id === id);
187
+ if (index === -1)
188
+ return;
189
+ const result = reorderFn(layer.components, index);
190
+ if (result !== false) {
191
+ this.#updateDisplayOrder(layer);
192
+ }
193
+ }
194
+ #findLayerByComponentId(componentId) {
195
+ const layers = this.layersManager.getAll();
196
+ return layers.find((layer) => layer.components.some((c) => c.id === componentId));
197
+ }
198
+ #updateDisplayOrder(layer) {
199
+ const displayObject = layer.displayObject;
200
+ if (!displayObject)
201
+ return;
202
+ // Sync displayObject children order with components array
203
+ layer.components.forEach((component, index) => {
204
+ if (component.displayObject) {
205
+ displayObject.setChildIndex(component.displayObject, index);
206
+ }
207
+ });
208
+ }
209
+ bulkUpdate(updates) {
210
+ updates.forEach(({ id, data }) => this.update(id, data));
211
+ }
212
+ bulkDelete(ids) {
213
+ ids.forEach((id) => this.delete(id));
214
+ }
215
+ async hide(id) {
216
+ const component = this.get(id);
217
+ if (component) {
218
+ await component.props.setVisible(false);
219
+ }
220
+ }
221
+ async show(id) {
222
+ const component = this.get(id);
223
+ if (component) {
224
+ await component.props.setVisible(true);
225
+ }
226
+ }
227
+ async toggle(id) {
228
+ const component = this.get(id);
229
+ if (component) {
230
+ await component.props.setVisible(!component.props.visible);
231
+ }
232
+ }
233
+ filter(predicate) {
234
+ return this.getAll().filter(predicate);
235
+ }
236
+ isComponentVisible(componentId) {
237
+ const component = this.get(componentId);
238
+ if (!component) {
239
+ return false;
240
+ }
241
+ return this.isVisible(component);
242
+ }
243
+ destroy() {
244
+ this.eventManager.removeEventListener('subtitleschange', this.debouncedRefreshSubtitles);
245
+ this.debouncedRefreshSubtitles.cancel(); // Cancel any pending debounced calls
246
+ }
247
+ }
@@ -0,0 +1,18 @@
1
+ import type { RenderEnvironment } from '..';
2
+ import { StateManager } from './StateManager.svelte.js';
3
+ export declare class DomManager {
4
+ #private;
5
+ private state;
6
+ private env;
7
+ private sceneContainer;
8
+ constructor(cradle: {
9
+ stateManager: StateManager;
10
+ environment: RenderEnvironment;
11
+ containerElement: HTMLDivElement;
12
+ });
13
+ get canvas(): HTMLCanvasElement;
14
+ get htmlContainer(): HTMLDivElement;
15
+ scale(scale: number): void;
16
+ destroy(): void;
17
+ removeLoader(): void;
18
+ }
@@ -0,0 +1,73 @@
1
+ import { StateManager } from './StateManager.svelte.js';
2
+ export class DomManager {
3
+ #canvas;
4
+ #htmlContainer;
5
+ #loader;
6
+ state;
7
+ env;
8
+ sceneContainer;
9
+ constructor(cradle) {
10
+ this.state = cradle.stateManager;
11
+ this.env = cradle.environment; // Environment
12
+ this.sceneContainer = cradle.containerElement; // ContainerElement
13
+ this.#initialize();
14
+ }
15
+ get canvas() {
16
+ return this.#canvas;
17
+ }
18
+ get htmlContainer() {
19
+ return this.#htmlContainer;
20
+ }
21
+ #initialize() {
22
+ this.#loader = this.sceneContainer.appendChild(document.createElement('div'));
23
+ this.#loader.style.width = '100%';
24
+ this.#loader.style.height = '100%';
25
+ this.#loader.style.position = 'absolute';
26
+ this.#loader.style.top = '0';
27
+ this.#loader.style.left = '0';
28
+ this.#loader.style.background = `
29
+ linear-gradient(
30
+ 90deg,
31
+ #f0f0f0 0%,
32
+ #ccc 50%,
33
+ #f0f0f0 100%
34
+ )
35
+ `;
36
+ this.#loader.style.backgroundSize = '200% 100%';
37
+ this.#loader.style.animation = 'shimmer 4s infinite linear';
38
+ this.sceneContainer.style.overflow = 'hidden';
39
+ this.sceneContainer.style.position = 'relative';
40
+ this.#canvas = this.sceneContainer.appendChild(document.createElement('canvas'));
41
+ this.#canvas.style.position = 'absolute';
42
+ this.#canvas.style.pointerEvents = 'none';
43
+ this.#htmlContainer = this.sceneContainer.appendChild(document.createElement('div'));
44
+ this.#htmlContainer.style.transformOrigin = '0 0';
45
+ this.#htmlContainer.style.transform = `scale(${this.state.scale})`;
46
+ this.#htmlContainer.style.position = 'relative';
47
+ this.#htmlContainer.style.width = this.state.width + 'px';
48
+ this.#htmlContainer.style.height = this.state.height + 'px';
49
+ if (this.env === 'server') {
50
+ this.#htmlContainer.style.position = 'absolute';
51
+ this.#htmlContainer.style.top = '-10000px';
52
+ this.#htmlContainer.style.left = '-10000px';
53
+ }
54
+ }
55
+ scale(scale) {
56
+ const clampedScale = Math.max(0.01, Math.min(scale, 2));
57
+ this.state.setScale(clampedScale);
58
+ this.#htmlContainer.style.transform = `scale(${clampedScale})`;
59
+ const { width, height } = this.state;
60
+ this.sceneContainer.style.width = Math.round(width * clampedScale) + 'px';
61
+ this.sceneContainer.style.height = Math.round(height * clampedScale) + 'px';
62
+ }
63
+ destroy() {
64
+ this.#canvas.remove();
65
+ this.#htmlContainer.remove();
66
+ this.#loader?.remove();
67
+ }
68
+ removeLoader() {
69
+ if (this.#loader) {
70
+ this.#loader.remove();
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,7 @@
1
+ import type { EventType, EventPayload, EventMap } from '..';
2
+ export declare class EventManager extends EventTarget {
3
+ isReady: boolean;
4
+ constructor();
5
+ emit<T extends EventType>(event: T, props?: EventPayload<T>): void;
6
+ on<K extends keyof EventMap>(event: K, callback: (event: CustomEvent<EventMap[K]>) => void, options?: boolean | AddEventListenerOptions): void;
7
+ }
@@ -0,0 +1,22 @@
1
+ export class EventManager extends EventTarget {
2
+ isReady = false;
3
+ constructor() {
4
+ super();
5
+ }
6
+ emit(event, props) {
7
+ if (!this.isReady) {
8
+ return;
9
+ }
10
+ // Note: 'subtitleschange' is NOT in this list - subtitle refreshes are handled
11
+ // by ComponentsManager with debouncing to avoid blocking the main thread
12
+ const rerenderableEvents = ['layerschange', 'componentschange', 'componentchange'];
13
+ if (rerenderableEvents.includes(event)) {
14
+ this.emit('rerender');
15
+ }
16
+ this.dispatchEvent(new CustomEvent(event, { detail: props }));
17
+ }
18
+ // "on" automatically returns the right type under event.details object
19
+ on(event, callback, options) {
20
+ this.addEventListener(event, ((e) => callback(e)), options);
21
+ }
22
+ }