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,255 @@
1
+ import { AnimationSetup } from './AnimationSetup.js';
2
+ import { get } from 'lodash-es';
3
+ import { v4 as uuidv4 } from 'uuid';
4
+ export class AnimationBuilder {
5
+ animationContext;
6
+ engineAdaptor;
7
+ mainTimeline;
8
+ labels = new Set();
9
+ constructor(animationContext, engineAdaptor) {
10
+ this.animationContext = animationContext;
11
+ this.engineAdaptor = engineAdaptor;
12
+ const revertAfterComplete = get(this.animationContext.preset.preset, 'revertAfterComplete', false);
13
+ this.mainTimeline = this.engineAdaptor.createTimeline({
14
+ // duration: this.animationContext.preset.duration,
15
+ revertAfterComplete
16
+ });
17
+ }
18
+ build() {
19
+ this.processSetupSteps();
20
+ const hasItems = this.buildTimelineItems();
21
+ // No more repositionOutLabelsIfNeeded() since we position correctly from the start
22
+ return hasItems ? this.mainTimeline : null;
23
+ }
24
+ processSetupSteps() {
25
+ const setupProcessor = new AnimationSetup(this.animationContext, this.engineAdaptor);
26
+ setupProcessor.process();
27
+ }
28
+ ensureItemHasId(item) {
29
+ if (!item.id) {
30
+ item.id = uuidv4();
31
+ }
32
+ }
33
+ buildTimelineItems() {
34
+ const timelineItems = this.animationContext.preset.getTimelineItems();
35
+ let hasSequenceItems = false;
36
+ for (let i = 0; i < timelineItems.length; i++) {
37
+ const item = timelineItems[i];
38
+ this.ensureItemHasId(item);
39
+ const targets = this.resolveTargets(item.target);
40
+ if (!this.isValidTargets(targets)) {
41
+ console.warn(`AnimationBuilder: No targets found for query "${item.target}" in item ID "${item.id || 'untitled'}". Skipping.`);
42
+ continue;
43
+ }
44
+ this.addSequenceItemToTimeline(item, i === 0, targets);
45
+ hasSequenceItems = true;
46
+ }
47
+ return hasSequenceItems;
48
+ }
49
+ isValidTargets(targets) {
50
+ return targets !== null && !(Array.isArray(targets) && targets.length === 0);
51
+ }
52
+ addSequenceItemToTimeline(item, isFirstItem, targets) {
53
+ // Always build the child timeline first to get real duration
54
+ const childTimeline = this.processTweens(item, targets);
55
+ const duration = this.engineAdaptor.totalDuration(childTimeline);
56
+ // Now calculate position with duration information available
57
+ const resolvedPosition = this.calculatePosition(item.position, item.id, isFirstItem, duration);
58
+ // Add label if needed
59
+ this.addItemLabelIfNeeded(item, resolvedPosition);
60
+ // Add child timeline at calculated position
61
+ this.mainTimeline.add(childTimeline, resolvedPosition.value);
62
+ }
63
+ addItemLabelIfNeeded(item, resolvedPosition) {
64
+ if (item.id && resolvedPosition.value !== undefined && !this.labels.has(item.id)) {
65
+ this.engineAdaptor.addLabel(this.mainTimeline, item.id, resolvedPosition.value);
66
+ this.labels.add(item.id);
67
+ }
68
+ }
69
+ processTweens(item, targets) {
70
+ const tweenTL = this.engineAdaptor.createTimeline();
71
+ item.tweens.forEach((tweenDef, tweenIndex) => {
72
+ const resolvedVars = this.resolveTweenVars(tweenDef.vars);
73
+ const tweenPosition = tweenIndex === 0 ? 0 : '>'; // Always start first tween at 0
74
+ const tweenFinalPosition = tweenDef.position || tweenPosition;
75
+ const resolvedPosition = this.calculatePosition(tweenFinalPosition, undefined, tweenIndex === 0, 0);
76
+ this.engineAdaptor.addTween(tweenTL, targets, tweenDef.method, resolvedVars, resolvedPosition.value);
77
+ });
78
+ return tweenTL;
79
+ }
80
+ resolveTargets(targetQuery) {
81
+ return targetQuery
82
+ ? this.animationContext.getElement(targetQuery)
83
+ : this.animationContext.rootElement;
84
+ }
85
+ resolveTweenVars(vars) {
86
+ const resolved = {};
87
+ for (const [key, valueDefinition] of Object.entries(vars)) {
88
+ if (key === 'from' && this.isObject(valueDefinition)) {
89
+ resolved.from = this.resolveTweenVars(valueDefinition);
90
+ continue;
91
+ }
92
+ if (key === 'stagger' && valueDefinition) {
93
+ resolved.stagger = this.engineAdaptor.resolveStagger(valueDefinition, this.animationContext, typeof resolved.duration === 'number' ? resolved.duration : undefined);
94
+ continue;
95
+ }
96
+ // merge textShadow with animation shadow to preserve effects as expected
97
+ if (key === 'textShadow') {
98
+ const hasOriginalShadow = this.animationContext.getData('textShadow') &&
99
+ this.animationContext.getData('textShadow') !== 'none' &&
100
+ this.animationContext.getData('textShadow') !== '';
101
+ const hasAnimationShadow = valueDefinition && valueDefinition !== 'none' && valueDefinition !== '';
102
+ if (hasOriginalShadow && hasAnimationShadow) {
103
+ // merge shadows
104
+ resolved.textShadow = `${this.animationContext.getData('textShadow')}, ${valueDefinition}`;
105
+ }
106
+ else {
107
+ resolved.textShadow = valueDefinition;
108
+ }
109
+ continue;
110
+ }
111
+ resolved[key] = this.resolveValue(valueDefinition, key);
112
+ }
113
+ return resolved;
114
+ }
115
+ isObject(value) {
116
+ return typeof value === 'object' && value !== null;
117
+ }
118
+ resolveValue(valueDefinition, key) {
119
+ if (!this.isObject(valueDefinition)) {
120
+ return valueDefinition;
121
+ }
122
+ if (this.isFromDataValue(valueDefinition)) {
123
+ return this.resolveFromDataValue(valueDefinition, key);
124
+ }
125
+ if (this.isByIndexValue(valueDefinition)) {
126
+ return this.resolveByIndexValue(valueDefinition, key);
127
+ }
128
+ return valueDefinition;
129
+ }
130
+ isFromDataValue(value) {
131
+ return 'fromData' in value && !('type' in value && value.type === 'byIndex');
132
+ }
133
+ isByIndexValue(value) {
134
+ return value.type === 'byIndex' && 'expression' in value;
135
+ }
136
+ resolveFromDataValue(dataDef, key) {
137
+ const referencedData = this.animationContext.getData(dataDef.fromData);
138
+ if (referencedData === undefined) {
139
+ console.warn(`AnimationBuilder: dataKey "${dataDef.fromData}" for property "${key}" not found. Using fallbackValue if provided.`);
140
+ return dataDef.fallbackValue;
141
+ }
142
+ if (Array.isArray(referencedData)) {
143
+ return this.createArrayAccessFunction(referencedData, dataDef);
144
+ }
145
+ return referencedData;
146
+ }
147
+ createArrayAccessFunction(valuesArray, dataDef) {
148
+ const mode = dataDef.mode || 'cycle';
149
+ const fallback = dataDef.fallbackValue;
150
+ const arrayClone = [...valuesArray];
151
+ return (i) => {
152
+ if (arrayClone.length === 0)
153
+ return fallback;
154
+ if (i < arrayClone.length)
155
+ return arrayClone[i];
156
+ switch (mode) {
157
+ case 'cycle':
158
+ return arrayClone[i % arrayClone.length];
159
+ case 'clamp':
160
+ return arrayClone[arrayClone.length - 1];
161
+ default:
162
+ return fallback;
163
+ }
164
+ };
165
+ }
166
+ resolveByIndexValue(dynamicValueDef, key) {
167
+ const expr = dynamicValueDef.expression;
168
+ const dataContext = this.animationContext.getAllData();
169
+ try {
170
+ const boundExpressionFunc = new Function('index', 'data', `return (${expr})`);
171
+ return (i) => {
172
+ try {
173
+ return boundExpressionFunc(i, dataContext);
174
+ }
175
+ catch (e) {
176
+ console.warn(`AnimationBuilder: Error executing byIndex expression for '${key}': ${expr}. Index: ${i}. Using fallback.`, e);
177
+ return dynamicValueDef.fallbackValue;
178
+ }
179
+ };
180
+ }
181
+ catch (e) {
182
+ console.warn(`AnimationBuilder: Error creating function for byIndex expression '${expr}' for '${key}'. Using fallback.`, e);
183
+ return () => dynamicValueDef.fallbackValue;
184
+ }
185
+ }
186
+ calculatePosition(positionDef, itemId, isFirstItem, duration) {
187
+ if (positionDef === undefined) {
188
+ return { value: isFirstItem ? 0 : '>' };
189
+ }
190
+ if (typeof positionDef === 'string') {
191
+ return this.resolveStringPosition(positionDef, duration);
192
+ }
193
+ if (typeof positionDef === 'object') {
194
+ return this.resolveObjectPosition(positionDef);
195
+ }
196
+ if (typeof positionDef === 'number') {
197
+ return { value: positionDef };
198
+ }
199
+ return { value: 0 };
200
+ }
201
+ resolveStringPosition(positionDef, duration) {
202
+ switch (positionDef) {
203
+ case 'in':
204
+ return { value: 0 };
205
+ case 'out': {
206
+ const componentDuration = this.animationContext.getAnimationTargetDuration();
207
+ if (componentDuration !== undefined) {
208
+ const correctOutPosition = Math.max(0, componentDuration - duration);
209
+ return { value: correctOutPosition };
210
+ }
211
+ else {
212
+ console.warn('AnimationBuilder: Cannot position "out" animation - no component duration available');
213
+ return { value: '>' };
214
+ }
215
+ }
216
+ default:
217
+ return { value: positionDef };
218
+ }
219
+ }
220
+ resolveObjectPosition(positionDef) {
221
+ const { anchor, anchorPoint, alignTween = 'start', offset = '0s' } = positionDef;
222
+ const baseTime = this.resolveAnchor(anchor, anchorPoint);
223
+ if (baseTime === undefined) {
224
+ console.warn(`AnimationBuilder: Could not resolve anchor "${anchor}" for position.`);
225
+ return { value: 0 };
226
+ }
227
+ if (alignTween === 'end' || alignTween === 'center') {
228
+ console.warn(`AnimationBuilder: alignTween "${alignTween}" requires knowing the duration of the current animation block. This is advanced and may not be fully supported.`);
229
+ }
230
+ return { value: this.buildPositionString(baseTime, offset) };
231
+ }
232
+ resolveAnchor(anchor, anchorPoint) {
233
+ switch (anchor) {
234
+ case 'componentStart':
235
+ return 0;
236
+ case 'componentCenter': {
237
+ const cd = this.animationContext.getDuration();
238
+ return cd !== undefined ? cd / 2 : undefined;
239
+ }
240
+ case 'componentEnd':
241
+ return this.animationContext.endAnchor;
242
+ default:
243
+ return anchorPoint === 'end' ? `${anchor}.end` : anchor;
244
+ }
245
+ }
246
+ buildPositionString(baseTime, offset) {
247
+ if (offset === '0s' || offset === '0') {
248
+ return `${baseTime}`;
249
+ }
250
+ if (offset.startsWith('+') || offset.startsWith('-')) {
251
+ return `${baseTime}${offset}`;
252
+ }
253
+ return `${baseTime}+=${offset}`;
254
+ }
255
+ }
@@ -0,0 +1,7 @@
1
+ import { type AnimationPreset as AnimationPresetData, type AnimationPresetInput, type AnimationSequenceItem } from '..';
2
+ export declare class AnimationPreset {
3
+ preset: AnimationPresetData;
4
+ constructor(presetJson: AnimationPresetInput);
5
+ get duration(): number;
6
+ getTimelineItems(): AnimationSequenceItem[];
7
+ }
@@ -0,0 +1,31 @@
1
+ import { AnimationPresetShape } from '..';
2
+ import { get } from 'lodash-es';
3
+ export class AnimationPreset {
4
+ preset;
5
+ constructor(presetJson) {
6
+ const parsedPreset = AnimationPresetShape.safeParse(presetJson);
7
+ if (!parsedPreset.success) {
8
+ console.error('Invalid preset JSON', presetJson);
9
+ throw new Error('Invalid preset JSON');
10
+ }
11
+ this.preset = parsedPreset.data;
12
+ }
13
+ get duration() {
14
+ if (this.preset.duration) {
15
+ return Math.max(0.5, this.preset.duration);
16
+ }
17
+ const offset = Math.min(0.5, get(this.preset, 'startAt', 0.5));
18
+ const timeline = this.getTimelineItems();
19
+ let durations = 0;
20
+ if (timeline.length > 0) {
21
+ durations = timeline
22
+ .map((item) => item.tweens.map((tween) => typeof tween.vars.duration === 'number' ? tween.vars.duration : 0.5))
23
+ .reduce((acc, curr) => acc + curr.map((d) => d || 0.5).reduce((acc, curr) => acc + curr, 0), 0);
24
+ }
25
+ durations = parseFloat(durations.toFixed(2));
26
+ return durations + offset;
27
+ }
28
+ getTimelineItems() {
29
+ return this.preset.timeline;
30
+ }
31
+ }
@@ -0,0 +1,43 @@
1
+ import type { AnimationPreset, AnimationSequenceItem, SetupStep, TweenVars } from '../..';
2
+ export declare class AnimationPresetFactory {
3
+ static create(id: string): PresetComposer;
4
+ static from(preset: AnimationPreset): PresetComposer;
5
+ }
6
+ declare class PresetComposer {
7
+ private _id;
8
+ private _data;
9
+ private _setup;
10
+ private _timeline;
11
+ private _description?;
12
+ constructor(id: string);
13
+ withData(data: Record<string, any>): PresetComposer;
14
+ withSetup(setup: SetupStep[]): PresetComposer;
15
+ withTimeline(timeline: AnimationSequenceItem[]): PresetComposer;
16
+ withDescription(description: string): PresetComposer;
17
+ resetTimeline(): PresetComposer;
18
+ timeline(): TimelineComposer;
19
+ build(): AnimationPreset;
20
+ }
21
+ declare class TimelineComposer {
22
+ private _presetComposer;
23
+ private _timeline;
24
+ constructor(presetComposer: PresetComposer, existingTimeline?: any[]);
25
+ target(targetQuery: string): TargetComposer;
26
+ get timeline(): any[];
27
+ updateTimeline(): PresetComposer;
28
+ build(): AnimationPreset;
29
+ }
30
+ declare class TargetComposer {
31
+ private _timelineComposer;
32
+ private _timelineIndex;
33
+ private _timeline;
34
+ constructor(timelineComposer: TimelineComposer, timelineIndex: number);
35
+ to(vars: TweenVars, position?: string | number): TargetComposer;
36
+ from(vars: TweenVars, position?: string | number): TargetComposer;
37
+ fromTo(vars: TweenVars, position?: string | number): TargetComposer;
38
+ set(vars: TweenVars, position?: string | number): TargetComposer;
39
+ position(pos: string | number): TargetComposer;
40
+ timeline(): TimelineComposer;
41
+ build(): AnimationPreset;
42
+ }
43
+ export {};
@@ -0,0 +1,139 @@
1
+ export class AnimationPresetFactory {
2
+ static create(id) {
3
+ return new PresetComposer(id);
4
+ }
5
+ static from(preset) {
6
+ // Create a new composer initialized with all properties from the existing preset
7
+ const composer = new PresetComposer(preset.id).withData(preset.data || {});
8
+ // Copy the setup steps if they exist
9
+ if (preset.setup && preset.setup.length > 0) {
10
+ composer.withSetup([...preset.setup]);
11
+ }
12
+ // Copy the timeline if it exists
13
+ if (preset.timeline && preset.timeline.length > 0) {
14
+ composer.withTimeline([...preset.timeline]);
15
+ }
16
+ // Copy any other properties we might want to preserve
17
+ if (preset.description) {
18
+ composer.withDescription(preset.description);
19
+ }
20
+ return composer;
21
+ }
22
+ }
23
+ class PresetComposer {
24
+ _id;
25
+ _data = {};
26
+ _setup = [];
27
+ _timeline = [];
28
+ _description;
29
+ constructor(id) {
30
+ this._id = id;
31
+ // Initialize with default preset or empty structure
32
+ }
33
+ withData(data) {
34
+ this._data = { ...this._data, ...data };
35
+ return this;
36
+ }
37
+ withSetup(setup) {
38
+ this._setup = [...setup];
39
+ return this;
40
+ }
41
+ withTimeline(timeline) {
42
+ this._timeline = [...timeline];
43
+ return this;
44
+ }
45
+ withDescription(description) {
46
+ this._description = description;
47
+ return this;
48
+ }
49
+ // Reset the timeline to start fresh
50
+ resetTimeline() {
51
+ this._timeline = [];
52
+ return this;
53
+ }
54
+ timeline() {
55
+ return new TimelineComposer(this, this._timeline);
56
+ }
57
+ build() {
58
+ // Construct and return the final animation preset
59
+ return {
60
+ id: this._id,
61
+ ...(this._description ? { description: this._description } : {}),
62
+ data: this._data,
63
+ setup: this._setup,
64
+ timeline: this._timeline
65
+ };
66
+ }
67
+ }
68
+ class TimelineComposer {
69
+ _presetComposer;
70
+ _timeline = [];
71
+ constructor(presetComposer, existingTimeline = []) {
72
+ this._presetComposer = presetComposer;
73
+ this._timeline = [...existingTimeline];
74
+ }
75
+ target(targetQuery) {
76
+ // Create a new sequence item for this target
77
+ const sequenceItem = {
78
+ target: targetQuery,
79
+ tweens: []
80
+ };
81
+ // Add it to the timeline
82
+ this._timeline.push(sequenceItem);
83
+ return new TargetComposer(this, this._timeline.length - 1);
84
+ }
85
+ // Public getter for timeline access
86
+ get timeline() {
87
+ return this._timeline;
88
+ }
89
+ // Allow updating the preset composer with the current timeline
90
+ updateTimeline() {
91
+ return this._presetComposer.withTimeline(this._timeline);
92
+ }
93
+ build() {
94
+ // Update the timeline before building
95
+ return this.updateTimeline().build();
96
+ }
97
+ }
98
+ class TargetComposer {
99
+ _timelineComposer;
100
+ _timelineIndex;
101
+ _timeline;
102
+ constructor(timelineComposer, timelineIndex) {
103
+ this._timelineComposer = timelineComposer;
104
+ this._timelineIndex = timelineIndex;
105
+ this._timeline = timelineComposer.timeline;
106
+ }
107
+ to(vars, position) {
108
+ this._timeline[this._timelineIndex].tweens.push({ method: 'to', vars, position });
109
+ return this;
110
+ }
111
+ from(vars, position) {
112
+ this._timeline[this._timelineIndex].tweens.push({ method: 'from', vars, position });
113
+ return this;
114
+ }
115
+ fromTo(vars, position) {
116
+ if (!vars.from) {
117
+ throw new Error('from is required for fromTo');
118
+ }
119
+ this._timeline[this._timelineIndex].tweens.push({ method: 'fromTo', vars, position });
120
+ return this;
121
+ }
122
+ set(vars, position) {
123
+ this._timeline[this._timelineIndex].tweens.push({ method: 'set', vars, position });
124
+ return this;
125
+ }
126
+ // Set the position of this timeline item
127
+ position(pos) {
128
+ this._timeline[this._timelineIndex].position = pos;
129
+ return this;
130
+ }
131
+ // Return to timeline context
132
+ timeline() {
133
+ return this._timelineComposer;
134
+ }
135
+ // Build the final preset
136
+ build() {
137
+ return this.timeline().build();
138
+ }
139
+ }
@@ -0,0 +1,16 @@
1
+ import type { Animation } from '../..';
2
+ import type { ComponentData } from '../..';
3
+ import type { SplitTextCache } from '../SplitTextCache.js';
4
+ export declare class LineHighlighterAnimationBuilder {
5
+ static build(data: ComponentData, target: HTMLElement, animationData: Record<string, any>, splitTextCache: SplitTextCache): Animation[];
6
+ private static createLineHighlightAnimations;
7
+ private static prepareHighlightStyles;
8
+ private static createHighlightAnimation;
9
+ private static createUnhighlightAnimation;
10
+ private static createBackgroundHighlightAnimation;
11
+ private static generateBackgroundElementId;
12
+ private static createBackgroundElement;
13
+ private static getBackgroundConfig;
14
+ private static initializeBackgroundElement;
15
+ private static buildBackgroundAnimation;
16
+ }
@@ -0,0 +1,183 @@
1
+ import { get } from 'lodash-es';
2
+ import { linesHighlighter } from '../presets/lines.js'; // Assuming this exists
3
+ import { AnimationPresetFactory } from './AnimationPresetFactory.js';
4
+ import { ColorTransformer } from '../../transformers/ColorTransformer.js';
5
+ export class LineHighlighterAnimationBuilder {
6
+ static build(data, target, animationData, splitTextCache) {
7
+ if (data.type !== 'TEXT') {
8
+ return [];
9
+ }
10
+ const activeLine = get(data, 'appearance.text.activeLine', null);
11
+ if (!activeLine || !activeLine.enabled) {
12
+ return [];
13
+ }
14
+ const config = {
15
+ activeLine,
16
+ data,
17
+ animationData,
18
+ target,
19
+ splitTextCache
20
+ };
21
+ return this.createLineHighlightAnimations(config);
22
+ }
23
+ static createLineHighlightAnimations(config) {
24
+ const animations = [];
25
+ const styles = this.prepareHighlightStyles(config);
26
+ // Create main highlight animation
27
+ const highlightAnimation = this.createHighlightAnimation(config.data.id, styles.highlight, config.animationData);
28
+ animations.push(highlightAnimation);
29
+ // Create unhighlight animation if needed
30
+ const unhighlightAnimation = this.createUnhighlightAnimation(config.data.id, styles.original, config.animationData);
31
+ if (unhighlightAnimation) {
32
+ animations.push(unhighlightAnimation);
33
+ }
34
+ // Create background highlight animation if needed
35
+ const backgroundAnimation = this.createBackgroundHighlightAnimation(config);
36
+ if (backgroundAnimation) {
37
+ animations.push(backgroundAnimation);
38
+ }
39
+ return animations;
40
+ }
41
+ static prepareHighlightStyles(config) {
42
+ const { activeLine, data } = config;
43
+ const highlightStyles = ColorTransformer.transform(activeLine.color, 'background');
44
+ const originalStyles = ColorTransformer.transform(data.appearance.text?.color, 'background');
45
+ // Handle font weight if specified
46
+ if (get(activeLine, 'fontWeight', undefined)) {
47
+ highlightStyles.fontWeight = activeLine.fontWeight;
48
+ originalStyles.fontWeight = data.appearance.text?.fontWeight ?? 'normal';
49
+ }
50
+ return {
51
+ highlight: highlightStyles,
52
+ original: originalStyles
53
+ };
54
+ }
55
+ static createHighlightAnimation(componentId, styles, animationData) {
56
+ const animation = AnimationPresetFactory.from(linesHighlighter)
57
+ .resetTimeline()
58
+ .timeline()
59
+ .target('lines')
60
+ .to({
61
+ ...styles,
62
+ stagger: { type: 'fromData', dataKey: 'lineStartTimes' } // Use line timing data
63
+ })
64
+ .build();
65
+ return {
66
+ id: `lines-highlight-${componentId}`,
67
+ name: 'Lines Highlight',
68
+ animation,
69
+ startAt: 0
70
+ };
71
+ }
72
+ static createUnhighlightAnimation(componentId, originalStyles, animationData) {
73
+ if (!animationData.lineUnhighlightTimes) {
74
+ return null;
75
+ }
76
+ const animation = AnimationPresetFactory.from(linesHighlighter)
77
+ .resetTimeline()
78
+ .timeline()
79
+ .target('lines')
80
+ .to({
81
+ ...originalStyles,
82
+ stagger: { type: 'fromData', dataKey: 'lineUnhighlightTimes' }
83
+ })
84
+ .build();
85
+ return {
86
+ id: `lines-highlight-${componentId}-unhighlight`,
87
+ name: 'Lines Unhighlight',
88
+ animation,
89
+ startAt: 0
90
+ };
91
+ }
92
+ static createBackgroundHighlightAnimation(config) {
93
+ const { activeLine, target, splitTextCache, data, animationData } = config;
94
+ if (!activeLine.backgroundColor) {
95
+ return null;
96
+ }
97
+ const lines = splitTextCache.getSplitText(target, 'lines');
98
+ if (!lines?.length) {
99
+ return null;
100
+ }
101
+ const bgHighlighter = this.createBackgroundElement(target, data.id);
102
+ const backgroundConfig = this.getBackgroundConfig(activeLine);
103
+ const bgStyles = ColorTransformer.transform(activeLine.backgroundColor, 'background');
104
+ this.initializeBackgroundElement(bgHighlighter, lines[0], backgroundConfig, bgStyles);
105
+ const animation = this.buildBackgroundAnimation(data.id, bgHighlighter.id, lines, animationData, backgroundConfig, bgStyles);
106
+ return {
107
+ id: `lines-background-highlight-${data.id}`,
108
+ name: 'Lines Background Highlight',
109
+ animation,
110
+ startAt: 0
111
+ };
112
+ }
113
+ static generateBackgroundElementId(componentId) {
114
+ return `highlighter-bg-lines-${componentId}`;
115
+ }
116
+ static createBackgroundElement(target, componentId) {
117
+ const bgHighlighter = document.createElement('div');
118
+ bgHighlighter.id = this.generateBackgroundElementId(componentId);
119
+ bgHighlighter.style.position = 'absolute';
120
+ bgHighlighter.style.pointerEvents = 'none';
121
+ target.prepend(bgHighlighter);
122
+ return bgHighlighter;
123
+ }
124
+ static getBackgroundConfig(activeLine) {
125
+ return {
126
+ paddingX: get(activeLine, 'backgroundPaddingX', 25),
127
+ paddingY: get(activeLine, 'backgroundPaddingY', 10),
128
+ borderRadius: get(activeLine, 'backgroundBorderRadius', 10)
129
+ };
130
+ }
131
+ static initializeBackgroundElement(bgHighlighter, firstLine, config, bgStyles) {
132
+ const { paddingX, paddingY, borderRadius } = config;
133
+ bgHighlighter.style.left = `${firstLine.offsetLeft - paddingX}px`;
134
+ bgHighlighter.style.top = `${firstLine.offsetTop - paddingY}px`;
135
+ bgHighlighter.style.width = `${firstLine.clientWidth + 2 * paddingX}px`;
136
+ bgHighlighter.style.height = `${firstLine.clientHeight + 2 * paddingY}px`;
137
+ bgHighlighter.style.borderRadius = `${borderRadius}px`;
138
+ bgHighlighter.style.opacity = '1';
139
+ if (bgStyles) {
140
+ Object.entries(bgStyles).forEach(([key, value]) => {
141
+ // Check if key is a valid writable style property
142
+ if (key in bgHighlighter.style) {
143
+ bgHighlighter.style[key] = String(value);
144
+ }
145
+ else {
146
+ // For custom properties or CSS variables, use setProperty
147
+ bgHighlighter.style.setProperty(key, String(value));
148
+ }
149
+ });
150
+ }
151
+ }
152
+ static buildBackgroundAnimation(componentId, backgroundElementId, lines, animationData, backgroundConfig, bgStyles) {
153
+ const presetComposer = AnimationPresetFactory.create(`lines-bg-highlight-anim-${componentId}`);
154
+ const timelineComposer = presetComposer.timeline();
155
+ const targetComposer = timelineComposer.target(`#${backgroundElementId}`);
156
+ const lineStartTimes = animationData.lineStartTimes ?? []; // Use line timing data
157
+ if (lineStartTimes.length <= 1) {
158
+ return timelineComposer.build();
159
+ }
160
+ const { paddingX, paddingY, borderRadius } = backgroundConfig;
161
+ for (let i = 0; i < lineStartTimes.length; i++) {
162
+ const currentLine = lines[i];
163
+ if (!currentLine) {
164
+ console.warn(`LineHighlighter: Line element at index ${i} is missing.`);
165
+ continue;
166
+ }
167
+ const startTime = parseFloat(lineStartTimes[i].toFixed(3));
168
+ targetComposer
169
+ .to({
170
+ borderRadius: `${borderRadius}px`,
171
+ left: currentLine.offsetLeft - paddingX,
172
+ top: currentLine.offsetTop - paddingY,
173
+ width: currentLine.clientWidth + 2 * paddingX,
174
+ height: currentLine.clientHeight + 2 * paddingY,
175
+ duration: 0.15,
176
+ ease: 'power1.out',
177
+ ...bgStyles
178
+ }, startTime)
179
+ .position(0);
180
+ }
181
+ return timelineComposer.build();
182
+ }
183
+ }