@twick/visualizer 0.14.0 → 0.14.3

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 (68) hide show
  1. package/.eslintrc.json +20 -20
  2. package/README.md +113 -13
  3. package/package.json +14 -14
  4. package/package.json.bak +34 -0
  5. package/src/animations/blur.tsx +96 -60
  6. package/src/animations/breathe.tsx +95 -60
  7. package/src/animations/fade.tsx +173 -60
  8. package/src/animations/index.ts +12 -0
  9. package/src/animations/photo-rise.tsx +103 -66
  10. package/src/animations/photo-zoom.tsx +109 -73
  11. package/src/animations/rise.tsx +157 -118
  12. package/src/animations/succession.tsx +112 -77
  13. package/src/components/frame-effects.tsx +188 -188
  14. package/src/components/track.tsx +237 -232
  15. package/src/controllers/animation.controller.ts +38 -38
  16. package/src/controllers/element.controller.ts +42 -42
  17. package/src/controllers/frame-effect.controller.tsx +29 -29
  18. package/src/controllers/text-effect.controller.ts +32 -32
  19. package/src/elements/audio.element.tsx +79 -17
  20. package/src/elements/caption.element.tsx +169 -87
  21. package/src/elements/circle.element.tsx +88 -20
  22. package/src/elements/icon.element.tsx +88 -20
  23. package/src/elements/image.element.tsx +134 -55
  24. package/src/elements/index.ts +14 -0
  25. package/src/elements/rect.element.tsx +92 -22
  26. package/src/elements/scene.element.tsx +97 -29
  27. package/src/elements/text.element.tsx +101 -27
  28. package/src/elements/video.element.tsx +274 -56
  29. package/src/frame-effects/circle.frame.tsx +168 -103
  30. package/src/frame-effects/index.ts +7 -0
  31. package/src/frame-effects/rect.frame.tsx +198 -103
  32. package/src/global.css +11 -11
  33. package/src/helpers/caption.utils.ts +29 -29
  34. package/src/helpers/constants.ts +162 -158
  35. package/src/helpers/element.utils.ts +331 -239
  36. package/src/helpers/event.utils.ts +21 -0
  37. package/src/helpers/filters.ts +127 -127
  38. package/src/helpers/log.utils.ts +55 -29
  39. package/src/helpers/timing.utils.ts +109 -109
  40. package/src/helpers/types.ts +361 -241
  41. package/src/helpers/utils.ts +36 -19
  42. package/src/index.ts +196 -6
  43. package/src/live.tsx +16 -16
  44. package/src/project.ts +6 -6
  45. package/src/sample.ts +247 -247
  46. package/src/text-effects/elastic.tsx +70 -39
  47. package/src/text-effects/erase.tsx +91 -58
  48. package/src/text-effects/index.ts +9 -0
  49. package/src/text-effects/stream-word.tsx +94 -60
  50. package/src/text-effects/typewriter.tsx +93 -59
  51. package/src/visualizer-grouped.ts +83 -0
  52. package/src/visualizer.tsx +182 -78
  53. package/tsconfig.json +11 -11
  54. package/typedoc.json +19 -14
  55. package/vite.config.ts +15 -15
  56. package/.turbo/turbo-build.log +0 -19
  57. package/.turbo/turbo-docs.log +0 -7
  58. package/LICENSE +0 -197
  59. package/dist/mp4.wasm +0 -0
  60. package/dist/project.css +0 -1
  61. package/dist/project.js +0 -145
  62. package/docs/.nojekyll +0 -1
  63. package/docs/README.md +0 -13
  64. package/docs/interfaces/Animation.md +0 -47
  65. package/docs/interfaces/Element.md +0 -47
  66. package/docs/interfaces/FrameEffectPlugin.md +0 -47
  67. package/docs/interfaces/TextEffect.md +0 -47
  68. package/docs/modules.md +0 -535
@@ -1,239 +1,331 @@
1
- import { all, Reference, waitFor } from "@twick/core";
2
- import { FrameState, ObjectFit, SizeVector, VisualizerElement } from "./types";
3
- import { OBJECT_FIT } from "./constants";
4
- import textEffectController from "../controllers/text-effect.controller";
5
- import animationController from "../controllers/animation.controller";
6
- import { View2D } from "@twick/2d";
7
- import frameEffectController from "../controllers/frame-effect.controller";
8
- import { logger } from "./log.utils";
9
-
10
- /**
11
- * Element utilities for the visualizer package.
12
- * Provides functions for handling element positioning, sizing, and transformations.
13
- */
14
-
15
- /**
16
- * Fits an element within specified bounds while maintaining aspect ratio
17
- * @param {Object} params - Parameters for fitting the element
18
- * @param {Object} params.containerSize - The container size
19
- * @param {Object} params.elementSize - The element size
20
- * @param {Object} params.elementRef - The element reference
21
- * @param {string} [params.objectFit] - The fit mode (contain, cover, fill)
22
- * @returns {Object} Updated element dimensions
23
- */
24
- export function* fitElement({
25
- containerSize,
26
- elementSize,
27
- elementRef,
28
- objectFit,
29
- }: {
30
- containerSize: SizeVector;
31
- elementSize: SizeVector;
32
- elementRef: Reference<any>;
33
- objectFit?: ObjectFit;
34
- }) {
35
- const containerAspectRatio = containerSize.x / containerSize.y;
36
- const elementAspectRatio = elementSize.x / elementSize.y;
37
- switch (objectFit) {
38
- case OBJECT_FIT.CONTAIN:
39
- if (elementAspectRatio > containerAspectRatio) {
40
- yield elementRef().size({
41
- x: containerSize.x,
42
- y: containerSize.x / elementAspectRatio,
43
- });
44
- yield elementRef().scale(
45
- containerSize.x / elementSize.x,
46
- (containerSize.x * elementAspectRatio) / elementSize.y
47
- );
48
- } else {
49
- yield elementRef().size({
50
- x: containerSize.y * elementAspectRatio,
51
- y: containerSize.y,
52
- });
53
- yield elementRef().scale(
54
- (containerSize.y * elementAspectRatio) / elementSize.x,
55
- containerSize.y / elementSize.y
56
- );
57
- }
58
- break;
59
- case OBJECT_FIT.COVER:
60
- if (elementAspectRatio > containerAspectRatio) {
61
- yield elementRef().size({
62
- x: containerSize.y * elementAspectRatio,
63
- y: containerSize.y,
64
- });
65
- yield elementRef().scale(
66
- (containerSize.y * elementAspectRatio) / elementSize.x,
67
- containerSize.y / elementSize.y
68
- );
69
- } else {
70
- yield elementRef().size({
71
- x: containerSize.x,
72
- y: containerSize.x / elementAspectRatio,
73
- });
74
- yield elementRef().scale(
75
- containerSize.x / elementSize.x,
76
- (containerSize.x * elementAspectRatio) / elementSize.y
77
- );
78
- }
79
- break;
80
- case OBJECT_FIT.FILL:
81
- yield elementRef().size(containerSize);
82
- yield elementRef().scale(
83
- containerSize.x / elementSize.x,
84
- containerSize.x / elementSize.y
85
- );
86
- break;
87
- default:
88
- break;
89
- }
90
- }
91
-
92
- export function* addTextEffect({
93
- elementRef,
94
- element,
95
- }: {
96
- elementRef: Reference<any>;
97
- element: VisualizerElement;
98
- }) {
99
- yield elementRef();
100
- if (element.textEffect) {
101
- const effect = textEffectController.get(element.textEffect.name);
102
- if (effect) {
103
- yield* effect.run({
104
- elementRef,
105
- duration: element.e - element.s,
106
- ...element.textEffect,
107
- });
108
- }
109
- }
110
- }
111
-
112
- export function* addAnimation({
113
- elementRef,
114
- containerRef,
115
- element,
116
- view,
117
- }: {
118
- elementRef: Reference<any>;
119
- containerRef?: Reference<any>;
120
- element: VisualizerElement;
121
- view: View2D;
122
- }) {
123
- yield elementRef();
124
- if (element.animation) {
125
- const animation = animationController.get(element.animation.name);
126
- if (animation) {
127
- yield* animation.run({
128
- elementRef,
129
- containerRef,
130
- view,
131
- duration: element.e - element.s,
132
- ...element.animation,
133
- });
134
- }
135
- }
136
- }
137
-
138
-
139
- export function* addFrameEffect({
140
- containerRef,
141
- elementRef,
142
- element,
143
- }: {
144
- containerRef: Reference<any>;
145
- elementRef: Reference<any>;
146
- element: VisualizerElement;
147
- }) {
148
- let frameEffects = [];
149
- const initProps = getFrameState({
150
- containerRef,
151
- elementRef,
152
- });
153
-
154
- for (let i = 0; i < element?.frameEffects?.length; i++) {
155
- const frameEffect = element.frameEffects[i];
156
- const restore =
157
- i === element.frameEffects.length - 1 ||
158
- element.frameEffects[i + 1].s !== frameEffect.e;
159
- const frameEffectPlugin = frameEffectController.get(frameEffect.name);
160
- if (frameEffectPlugin) {
161
- yield* frameEffectPlugin.run({
162
- containerRef,
163
- elementRef,
164
- initFrameState: initProps,
165
- frameEffect,
166
- });
167
- if (restore) {
168
- yield* restoreFrameState({
169
- containerRef,
170
- elementRef,
171
- duration: frameEffect.e - frameEffect.s,
172
- element,
173
- initProps,
174
- })
175
- }
176
- // frameEffects.push(...sequence);
177
-
178
- }
179
- }
180
- // yield* all(...frameEffects);
181
- }
182
-
183
- export function getFrameState({
184
- containerRef,
185
- elementRef,
186
- }: {
187
- containerRef: Reference<any>;
188
- elementRef: Reference<any>;
189
- }): FrameState {
190
- return {
191
- frame: {
192
- size: containerRef().size(),
193
- pos: containerRef().position(),
194
- radius: containerRef().radius(),
195
- scale: containerRef().scale(),
196
- rotation: containerRef().rotation(),
197
- },
198
- element: {
199
- size: containerRef().size(),
200
- pos: elementRef().position(),
201
- scale: elementRef().scale(),
202
- },
203
- }
204
- }
205
-
206
- export function* restoreFrameState({
207
- containerRef,
208
- elementRef,
209
- duration,
210
- element,
211
- initProps,
212
- }: {
213
- containerRef: Reference<any>;
214
- elementRef: Reference<any>;
215
- duration: number;
216
- element: VisualizerElement;
217
- initProps: FrameState;
218
- }) {
219
- yield* waitFor(duration);
220
- logger(`restoreFrameState: ${JSON.stringify(initProps)}`);
221
- let sequence = [];
222
- sequence.push(containerRef().size(initProps.frame.size));
223
- sequence.push(containerRef().position(initProps.frame.pos));
224
- sequence.push(containerRef().scale(initProps.frame.scale));
225
- sequence.push(containerRef().rotation(initProps.frame.rotation));
226
- sequence.push(containerRef().radius(initProps.frame.radius));
227
- sequence.push(elementRef().size(initProps.element.size));
228
- sequence.push(elementRef().position(initProps.element.pos));
229
- sequence.push(elementRef().scale(initProps.element.scale));
230
- sequence.push(
231
- fitElement({
232
- elementRef,
233
- containerSize: initProps.frame.size,
234
- elementSize: initProps.element.size,
235
- objectFit: element.objectFit ?? "none",
236
- })
237
- );
238
- yield* all(...sequence);
239
- }
1
+ import { all, Reference, waitFor } from "@twick/core";
2
+ import { FrameState, ObjectFit, SizeVector, VisualizerElement } from "./types";
3
+ import { OBJECT_FIT } from "./constants";
4
+ import textEffectController from "../controllers/text-effect.controller";
5
+ import animationController from "../controllers/animation.controller";
6
+ import { View2D } from "@twick/2d";
7
+ import frameEffectController from "../controllers/frame-effect.controller";
8
+ import { logger } from "./log.utils";
9
+
10
+ /**
11
+ * Element utilities for the visualizer package.
12
+ * Provides functions for handling element positioning, sizing, and transformations
13
+ * to ensure proper content display and visual effects.
14
+ */
15
+
16
+ /**
17
+ * Fits an element within specified bounds while maintaining aspect ratio.
18
+ * Handles different object-fit modes for proper content scaling and positioning.
19
+ *
20
+ * @param containerSize - The container size dimensions
21
+ * @param elementSize - The element size dimensions
22
+ * @param elementRef - The element reference to modify
23
+ * @param objectFit - The fit mode (contain, cover, fill, none)
24
+ * @returns Generator that controls the element fitting process
25
+ *
26
+ * @example
27
+ * ```js
28
+ * yield* fitElement({
29
+ * containerSize: { x: 800, y: 600 },
30
+ * elementSize: { x: 1920, y: 1080 },
31
+ * elementRef: videoElement,
32
+ * objectFit: "cover"
33
+ * });
34
+ * ```
35
+ */
36
+ export function* fitElement({
37
+ containerSize,
38
+ elementSize,
39
+ elementRef,
40
+ objectFit,
41
+ }: {
42
+ containerSize: SizeVector;
43
+ elementSize: SizeVector;
44
+ elementRef: Reference<any>;
45
+ objectFit?: ObjectFit;
46
+ }) {
47
+ const containerAspectRatio = containerSize.x / containerSize.y;
48
+ const elementAspectRatio = elementSize.x / elementSize.y;
49
+ switch (objectFit) {
50
+ case OBJECT_FIT.CONTAIN:
51
+ if (elementAspectRatio > containerAspectRatio) {
52
+ yield elementRef().size({
53
+ x: containerSize.x,
54
+ y: containerSize.x / elementAspectRatio,
55
+ });
56
+ yield elementRef().scale(
57
+ containerSize.x / elementSize.x,
58
+ (containerSize.x * elementAspectRatio) / elementSize.y
59
+ );
60
+ } else {
61
+ yield elementRef().size({
62
+ x: containerSize.y * elementAspectRatio,
63
+ y: containerSize.y,
64
+ });
65
+ yield elementRef().scale(
66
+ (containerSize.y * elementAspectRatio) / elementSize.x,
67
+ containerSize.y / elementSize.y
68
+ );
69
+ }
70
+ break;
71
+ case OBJECT_FIT.COVER:
72
+ if (elementAspectRatio > containerAspectRatio) {
73
+ yield elementRef().size({
74
+ x: containerSize.y * elementAspectRatio,
75
+ y: containerSize.y,
76
+ });
77
+ yield elementRef().scale(
78
+ (containerSize.y * elementAspectRatio) / elementSize.x,
79
+ containerSize.y / elementSize.y
80
+ );
81
+ } else {
82
+ yield elementRef().size({
83
+ x: containerSize.x,
84
+ y: containerSize.x / elementAspectRatio,
85
+ });
86
+ yield elementRef().scale(
87
+ containerSize.x / elementSize.x,
88
+ (containerSize.x * elementAspectRatio) / elementSize.y
89
+ );
90
+ }
91
+ break;
92
+ case OBJECT_FIT.FILL:
93
+ yield elementRef().size(containerSize);
94
+ yield elementRef().scale(
95
+ containerSize.x / elementSize.x,
96
+ containerSize.x / elementSize.y
97
+ );
98
+ break;
99
+ default:
100
+ break;
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Adds text effects to an element based on its configuration.
106
+ * Applies text animations like typewriter, stream word, or elastic effects.
107
+ *
108
+ * @param elementRef - Reference to the text element
109
+ * @param element - Element configuration containing text effect settings
110
+ * @returns Generator that controls the text effect animation
111
+ *
112
+ * @example
113
+ * ```js
114
+ * yield* addTextEffect({
115
+ * elementRef: textElement,
116
+ * element: {
117
+ * textEffect: {
118
+ * name: "typewriter",
119
+ * duration: 3,
120
+ * interval: 0.1
121
+ * }
122
+ * }
123
+ * });
124
+ * ```
125
+ */
126
+ export function* addTextEffect({
127
+ elementRef,
128
+ element,
129
+ }: {
130
+ elementRef: Reference<any>;
131
+ element: VisualizerElement;
132
+ }) {
133
+ yield elementRef();
134
+ if (element.textEffect) {
135
+ const effect = textEffectController.get(element.textEffect.name);
136
+ if (effect) {
137
+ yield* effect.run({
138
+ elementRef,
139
+ duration: element.e - element.s,
140
+ ...element.textEffect,
141
+ });
142
+ }
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Adds animations to an element based on its configuration.
148
+ * Applies entrance, exit, or transition animations to elements.
149
+ *
150
+ * @param elementRef - Reference to the element to animate
151
+ * @param containerRef - Optional reference to the container element
152
+ * @param element - Element configuration containing animation settings
153
+ * @param view - The main scene view for rendering
154
+ * @returns Generator that controls the animation timeline
155
+ *
156
+ * @example
157
+ * ```js
158
+ * yield* addAnimation({
159
+ * elementRef: videoElement,
160
+ * containerRef: frameContainer,
161
+ * element: {
162
+ * animation: {
163
+ * name: "fade",
164
+ * animate: "enter",
165
+ * duration: 2,
166
+ * direction: "center"
167
+ * }
168
+ * },
169
+ * view: sceneView
170
+ * });
171
+ * ```
172
+ */
173
+ export function* addAnimation({
174
+ elementRef,
175
+ containerRef,
176
+ element,
177
+ view,
178
+ }: {
179
+ elementRef: Reference<any>;
180
+ containerRef?: Reference<any>;
181
+ element: VisualizerElement;
182
+ view: View2D;
183
+ }) {
184
+ yield elementRef();
185
+ if (element.animation) {
186
+ const animation = animationController.get(element.animation.name);
187
+ if (animation) {
188
+ yield* animation.run({
189
+ elementRef,
190
+ containerRef,
191
+ view,
192
+ duration: element.e - element.s,
193
+ ...element.animation,
194
+ });
195
+ }
196
+ }
197
+ }
198
+
199
+
200
+ /**
201
+ * Adds frame effects to an element based on its configuration.
202
+ * Applies visual masks and containers like circular or rectangular frames.
203
+ *
204
+ * @param containerRef - Reference to the frame container element
205
+ * @param elementRef - Reference to the content element inside the frame
206
+ * @param element - Element configuration containing frame effect settings
207
+ * @returns Generator that controls the frame effect timeline
208
+ *
209
+ * @example
210
+ * ```js
211
+ * yield* addFrameEffect({
212
+ * containerRef: frameContainer,
213
+ * elementRef: contentElement,
214
+ * element: {
215
+ * frameEffects: [{
216
+ * name: "circle",
217
+ * s: 0,
218
+ * e: 10,
219
+ * props: {
220
+ * frameSize: [400, 400],
221
+ * frameShape: "circle",
222
+ * framePosition: { x: 960, y: 540 },
223
+ * radius: 200,
224
+ * objectFit: "cover"
225
+ * }
226
+ * }]
227
+ * }
228
+ * });
229
+ * ```
230
+ */
231
+ export function* addFrameEffect({
232
+ containerRef,
233
+ elementRef,
234
+ element,
235
+ }: {
236
+ containerRef: Reference<any>;
237
+ elementRef: Reference<any>;
238
+ element: VisualizerElement;
239
+ }) {
240
+ let frameEffects = [];
241
+ const initProps = getFrameState({
242
+ containerRef,
243
+ elementRef,
244
+ });
245
+
246
+ for (let i = 0; i < element?.frameEffects?.length; i++) {
247
+ const frameEffect = element.frameEffects[i];
248
+ const restore =
249
+ i === element.frameEffects.length - 1 ||
250
+ element.frameEffects[i + 1].s !== frameEffect.e;
251
+ const frameEffectPlugin = frameEffectController.get(frameEffect.name);
252
+ if (frameEffectPlugin) {
253
+ yield* frameEffectPlugin.run({
254
+ containerRef,
255
+ elementRef,
256
+ initFrameState: initProps,
257
+ frameEffect,
258
+ });
259
+ if (restore) {
260
+ yield* restoreFrameState({
261
+ containerRef,
262
+ elementRef,
263
+ duration: frameEffect.e - frameEffect.s,
264
+ element,
265
+ initProps,
266
+ })
267
+ }
268
+ // frameEffects.push(...sequence);
269
+
270
+ }
271
+ }
272
+ // yield* all(...frameEffects);
273
+ }
274
+
275
+ export function getFrameState({
276
+ containerRef,
277
+ elementRef,
278
+ }: {
279
+ containerRef: Reference<any>;
280
+ elementRef: Reference<any>;
281
+ }): FrameState {
282
+ return {
283
+ frame: {
284
+ size: containerRef().size(),
285
+ pos: containerRef().position(),
286
+ radius: containerRef().radius(),
287
+ scale: containerRef().scale(),
288
+ rotation: containerRef().rotation(),
289
+ },
290
+ element: {
291
+ size: containerRef().size(),
292
+ pos: elementRef().position(),
293
+ scale: elementRef().scale(),
294
+ },
295
+ }
296
+ }
297
+
298
+ export function* restoreFrameState({
299
+ containerRef,
300
+ elementRef,
301
+ duration,
302
+ element,
303
+ initProps,
304
+ }: {
305
+ containerRef: Reference<any>;
306
+ elementRef: Reference<any>;
307
+ duration: number;
308
+ element: VisualizerElement;
309
+ initProps: FrameState;
310
+ }) {
311
+ yield* waitFor(duration);
312
+ logger(`restoreFrameState: ${JSON.stringify(initProps)}`);
313
+ let sequence = [];
314
+ sequence.push(containerRef().size(initProps.frame.size));
315
+ sequence.push(containerRef().position(initProps.frame.pos));
316
+ sequence.push(containerRef().scale(initProps.frame.scale));
317
+ sequence.push(containerRef().rotation(initProps.frame.rotation));
318
+ sequence.push(containerRef().radius(initProps.frame.radius));
319
+ sequence.push(elementRef().size(initProps.element.size));
320
+ sequence.push(elementRef().position(initProps.element.pos));
321
+ sequence.push(elementRef().scale(initProps.element.scale));
322
+ sequence.push(
323
+ fitElement({
324
+ elementRef,
325
+ containerSize: initProps.frame.size,
326
+ elementSize: initProps.element.size,
327
+ objectFit: element.objectFit ?? "none",
328
+ })
329
+ );
330
+ yield* all(...sequence);
331
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Dispatches a custom event to the window object.
3
+ * Creates and dispatches a CustomEvent with the specified name and detail
4
+ * if running in a browser environment.
5
+ *
6
+ * @param eventName - The name of the custom event to dispatch
7
+ * @param detail - The event detail object to include with the event
8
+ * @returns True if the event was dispatched successfully, false otherwise
9
+ *
10
+ * @example
11
+ * ```js
12
+ * dispatchWindowEvent("playerUpdate", { status: "ready", playerId: "123" });
13
+ * // Dispatches a custom event with player update information
14
+ * ```
15
+ */
16
+ export const dispatchWindowEvent = (eventName: string, detail: any) => {
17
+ if (typeof window !== "undefined") {
18
+ const event = new CustomEvent(eventName, detail as any);
19
+ return window.dispatchEvent(event);
20
+ }
21
+ };