@twick/visualizer 0.0.1 → 0.14.2

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 (53) hide show
  1. package/.eslintrc.json +20 -20
  2. package/README.md +12 -12
  3. package/package.json +34 -31
  4. package/package.json.bak +34 -0
  5. package/src/animations/blur.tsx +60 -0
  6. package/src/animations/breathe.tsx +60 -0
  7. package/src/animations/fade.tsx +60 -0
  8. package/src/animations/photo-rise.tsx +66 -0
  9. package/src/animations/photo-zoom.tsx +73 -0
  10. package/src/animations/rise.tsx +118 -0
  11. package/src/animations/succession.tsx +77 -0
  12. package/src/components/frame-effects.tsx +188 -190
  13. package/src/components/track.tsx +237 -0
  14. package/src/controllers/animation.controller.ts +39 -0
  15. package/src/controllers/element.controller.ts +43 -0
  16. package/src/controllers/frame-effect.controller.tsx +30 -0
  17. package/src/controllers/text-effect.controller.ts +33 -0
  18. package/src/elements/audio.element.tsx +17 -0
  19. package/src/elements/caption.element.tsx +87 -0
  20. package/src/elements/circle.element.tsx +20 -0
  21. package/src/elements/icon.element.tsx +20 -0
  22. package/src/elements/image.element.tsx +53 -0
  23. package/src/elements/rect.element.tsx +22 -0
  24. package/src/elements/scene.element.tsx +29 -0
  25. package/src/elements/text.element.tsx +28 -0
  26. package/src/elements/video.element.tsx +55 -0
  27. package/src/frame-effects/circle.frame.tsx +103 -0
  28. package/src/frame-effects/rect.frame.tsx +103 -0
  29. package/src/global.css +11 -11
  30. package/src/helpers/caption.utils.ts +30 -40
  31. package/src/helpers/constants.ts +162 -158
  32. package/src/helpers/element.utils.ts +239 -85
  33. package/src/helpers/event.utils.ts +6 -0
  34. package/src/helpers/filters.ts +127 -127
  35. package/src/helpers/log.utils.ts +29 -32
  36. package/src/helpers/timing.utils.ts +110 -129
  37. package/src/helpers/types.ts +242 -146
  38. package/src/helpers/utils.ts +20 -0
  39. package/src/index.ts +6 -4
  40. package/src/live.tsx +16 -16
  41. package/src/project.ts +6 -6
  42. package/src/sample.ts +247 -449
  43. package/src/text-effects/elastic.tsx +39 -0
  44. package/src/text-effects/erase.tsx +58 -0
  45. package/src/text-effects/stream-word.tsx +60 -0
  46. package/src/text-effects/typewriter.tsx +59 -0
  47. package/src/visualizer.tsx +98 -78
  48. package/tsconfig.json +11 -10
  49. package/typedoc.json +14 -14
  50. package/vite.config.ts +15 -15
  51. package/src/components/animation.tsx +0 -7
  52. package/src/components/element.tsx +0 -344
  53. package/src/components/timeline.tsx +0 -225
@@ -1,344 +0,0 @@
1
- /**
2
- * Element component that handles the creation and management of visual elements
3
- * with various properties like position, size, rotation, and effects.
4
- */
5
-
6
- import { createRef, waitFor, all, Reference, Color } from "@revideo/core";
7
- import { Audio, Circle, Icon, Img, Rect, Txt, Video } from "@revideo/2d";
8
- import { logger } from "../helpers/log.utils";
9
- import {
10
- DEFAULT_BACKGROUND_COLOR,
11
- ELEMENT_TYPES,
12
- TRANSPARENT_COLOR,
13
- } from "../helpers/constants";
14
- import { fitElement } from "../helpers/element.utils";
15
- import { applyColorFilter } from "../helpers/filters";
16
- import { addFrameEffect } from "./frame-effects";
17
- import { Caption, CaptionProps, VisualizerElement } from "../helpers/types";
18
- import { splitPhraseTiming } from "../helpers/caption.utils";
19
- import { addAnimations } from "./animation";
20
-
21
-
22
- export function* addMediaElement({
23
- containerRef,
24
- element,
25
- mediaType,
26
- waitOnStart = true,
27
- }: {
28
- containerRef: Reference<any>;
29
- element: VisualizerElement;
30
- mediaType: string;
31
- waitOnStart?: boolean;
32
- }) {
33
- if (waitOnStart) {
34
- yield* waitFor(element.s);
35
- }
36
- const frameContainerRef = createRef<any>();
37
- const frameElementRef = createRef<any>();
38
- if (mediaType === ELEMENT_TYPES.VIDEO) {
39
- const frameProps = element.frame || element.props;
40
- logger(`Adding video element ${element.id}`);
41
- yield containerRef().add(
42
- <Rect ref={frameContainerRef} key={element.id} {...frameProps}>
43
- <Video
44
- ref={frameElementRef}
45
- key={`child-${element.id}`}
46
- {...element.props}
47
- />
48
- </Rect>
49
- );
50
- } else if (mediaType === ELEMENT_TYPES.IMAGE) {
51
- logger(`Adding image element ${element.id}`);
52
- yield containerRef().add(
53
- <Rect ref={frameContainerRef} key={element.id} {...element.frame}>
54
- <Img
55
- ref={frameElementRef}
56
- key={`child-${element.id}`}
57
- {...element.props}
58
- />
59
- </Rect>
60
- );
61
- }
62
- if (frameContainerRef()) {
63
- yield fitElement({
64
- elementRef: frameElementRef,
65
- containerSize: frameContainerRef().size(),
66
- elementSize: frameElementRef().size(),
67
- objectFit: element.objectFit,
68
- });
69
-
70
- if (element?.props?.mediaFilter) {
71
- applyColorFilter(frameElementRef, element.props.mediaFilter);
72
- }
73
-
74
- yield* all(
75
- addAnimations({
76
- elementRef: frameElementRef,
77
- }),
78
- addFrameEffect({
79
- containerRef: frameContainerRef,
80
- elementRef: frameElementRef,
81
- frameElement,
82
- }),
83
- waitFor(Math.max(0, element.e - element.s))
84
- );
85
- if (element.type === ELEMENT_TYPES.VIDEO) {
86
- yield frameElementRef().playing(false);
87
- }
88
- yield frameElementRef().remove();
89
- yield frameContainerRef().remove();
90
- }
91
- }
92
-
93
- export function* addCaptionElement({
94
- caption,
95
- captionProps,
96
- containerRef,
97
- capStyle,
98
- }: {
99
- caption: Caption;
100
- captionProps: CaptionProps;
101
- containerRef: Reference<any>;
102
- capStyle: string;
103
- }) {
104
- const words = splitPhraseTiming(caption);
105
- let phraseStart = 0;
106
- if (words?.length) {
107
- phraseStart = words[0].s;
108
- }
109
- let wordsState: {
110
- refs: Array<{ bgRef?: Reference<any>; textRef: Reference<any> }>;
111
- props: CaptionProps[];
112
- idx: number;
113
- prevTime: number;
114
- } = {
115
- refs: [],
116
- props: [],
117
- idx: 0,
118
- prevTime: phraseStart,
119
- };
120
-
121
- for (const word of words) {
122
- wordsState.props.push(captionProps);
123
- const textRef = createRef<Txt>();
124
- containerRef().add(
125
- <Txt ref={textRef} {...captionProps} text={word.t} opacity={0} />
126
- );
127
- if (capStyle == "highlight_bg") {
128
- const bgContainerRef = createRef();
129
- const childTextRef = createRef();
130
- containerRef().add(
131
- <Rect
132
- ref={bgContainerRef}
133
- fill={new Color(captionProps.colors.background).alpha(
134
- captionProps?.bgOpacity ?? 1
135
- )}
136
- width={textRef().width() + (captionProps.bgOffsetWidth ?? 30)}
137
- height={textRef().height() + (captionProps.bgOffsetHeight ?? 10)}
138
- margin={captionProps.bgMargin ?? [0, -5]}
139
- radius={captionProps.bgRadius ?? 10}
140
- padding={captionProps.bgPadding ?? [0, 15]}
141
- opacity={0}
142
- alignItems={"center"}
143
- justifyContent={"center"}
144
- layout
145
- >
146
- <Txt ref={childTextRef} {...captionProps} text={word.t} />
147
- </Rect>
148
- );
149
- textRef().remove();
150
- wordsState.refs.push({
151
- bgRef: bgContainerRef,
152
- textRef: childTextRef,
153
- });
154
- } else {
155
- wordsState.refs.push({
156
- textRef: textRef,
157
- });
158
- }
159
- wordsState.prevTime = word.e;
160
- wordsState.idx = wordsState.idx + 1;
161
- }
162
-
163
- wordsState.prevTime = phraseStart;
164
- wordsState.idx = 0;
165
-
166
- for (const word of words) {
167
- if (capStyle == "highlight_bg") {
168
- yield* wordsState.refs[wordsState.idx]?.bgRef?.().opacity(1, 0);
169
- yield* waitFor(Math.max(0, word.e - word.s));
170
- yield* wordsState.refs[wordsState.idx]
171
- ?.bgRef?.()
172
- .fill(TRANSPARENT_COLOR, 0);
173
- } else {
174
- yield* wordsState.refs[wordsState.idx]?.textRef?.().opacity(1, 0);
175
- yield* waitFor(Math.max(0, word.e - word.s));
176
- }
177
- wordsState.prevTime = word.e;
178
- wordsState.idx = wordsState.idx + 1;
179
- }
180
- }
181
-
182
- export function* makeSceneElements({
183
- containerRef,
184
- element,
185
- }: {
186
- containerRef: Reference<any>;
187
- element: VisualizerElement;
188
- }) {
189
- switch (element.type) {
190
- case ELEMENT_TYPES.RECT:
191
- yield* addSceneRectElement({ containerRef, element });
192
- break;
193
- case ELEMENT_TYPES.IMAGE:
194
- case ELEMENT_TYPES.VIDEO:
195
- const mediaContainerRef = createRef<any>();
196
- yield containerRef().add(
197
- <Rect
198
- ref={mediaContainerRef}
199
- fill={element.backgroundColor ?? DEFAULT_BACKGROUND_COLOR}
200
- size={"100%"}
201
- />
202
- );
203
- yield* addMediaElement({
204
- containerRef: mediaContainerRef,
205
- element,
206
- mediaType: element.type,
207
- waitOnStart: false,
208
- });
209
- yield mediaContainerRef().remove();
210
- break;
211
- default:
212
- yield* waitFor(Math.max(0, element.e - element.s));
213
- break;
214
- }
215
- }
216
-
217
- function* addSceneRectElement({
218
- containerRef,
219
- element,
220
- }: {
221
- containerRef: Reference<any>;
222
- element: VisualizerElement;
223
- }) {
224
- const elementRef = createRef<any>();
225
- let sequence: any[] = [];
226
- yield containerRef().add(
227
- <Rect ref={elementRef} key={element.id} {...element.props}></Rect>
228
- );
229
- for (const childElement of element.elements || []) {
230
- sequence.push(
231
- makeSceneElements({
232
- containerRef: elementRef,
233
- element: childElement,
234
- })
235
- );
236
- }
237
-
238
- yield* all(
239
- ...sequence,
240
- addAnimations({
241
- elementRef,
242
- }),
243
- waitFor(Math.max(0, element.e - element.s))
244
- );
245
- yield elementRef().remove();
246
- }
247
-
248
- export function* addRectElement({
249
- containerRef,
250
- element,
251
- }: {
252
- containerRef: Reference<any>;
253
- element: VisualizerElement;
254
- }) {
255
- const elementRef = createRef<any>();
256
- yield* waitFor(element?.s);
257
- yield containerRef().add(
258
- <Rect ref={elementRef} key={element.id} {...element.props} />
259
- );
260
- yield* all(
261
- addAnimations({ elementRef: elementRef }),
262
- waitFor(Math.max(0, element.e - element.s))
263
- );
264
- yield elementRef().remove();
265
- }
266
-
267
- export function* addTextElement({
268
- containerRef,
269
- element,
270
- }: {
271
- containerRef: Reference<any>;
272
- element: VisualizerElement;
273
- }) {
274
- const elementRef = createRef<any>();
275
- yield* waitFor(element?.s);
276
- yield containerRef().add(
277
- <Txt
278
- ref={elementRef}
279
- key={element.id}
280
- text={element.t}
281
- {...element.props}
282
- />
283
- );
284
- yield* all(
285
- addAnimations({ elementRef: elementRef }),
286
- waitFor(Math.max(0, element.e - element.s))
287
- );
288
- yield elementRef().remove();
289
- }
290
-
291
- export function* addCircleElement({
292
- containerRef,
293
- element,
294
- }: {
295
- containerRef: Reference<any>;
296
- element: VisualizerElement;
297
- }) {
298
- const elementRef = createRef<any>();
299
- yield* waitFor(element?.s);
300
- yield containerRef().add(
301
- <Circle ref={elementRef} key={element.id} {...element.props} />
302
- );
303
- yield* all(
304
- addAnimations({ elementRef: elementRef }),
305
- waitFor(Math.max(0, element.e - element.s))
306
- );
307
- yield elementRef().remove();
308
- }
309
-
310
- export function* addIconElement({
311
- containerRef,
312
- element,
313
- }: {
314
- containerRef: Reference<any>;
315
- element: VisualizerElement;
316
- }) {
317
- const elementRef = createRef<any>();
318
- yield* waitFor(element?.s);
319
- yield containerRef().add(
320
- <Icon ref={elementRef} key={element.id} {...element.props} />
321
- );
322
- yield* all(
323
- addAnimations({ elementRef: elementRef }),
324
- waitFor(Math.max(0, element.e - element.s))
325
- );
326
- yield elementRef().remove();
327
- }
328
-
329
- export function* addAudioElement({
330
- containerRef,
331
- element,
332
- }: {
333
- containerRef: Reference<any>;
334
- element: VisualizerElement;
335
- }) {
336
- const elementRef = createRef<any>();
337
- yield* waitFor(element?.s);
338
- yield containerRef().add(
339
- <Audio ref={elementRef} key={element.id} {...element.props} />
340
- );
341
- yield* waitFor(Math.max(0, element.e - element.s));
342
- yield elementRef().playing(false);
343
- yield elementRef().remove();
344
- }
@@ -1,225 +0,0 @@
1
- /**
2
- * Timeline component that handles the creation and management of different types of timelines
3
- * including video, audio, captions, scenes, and elements.
4
- */
5
-
6
- import { Layout, Rect, View2D, Audio } from "@revideo/2d";
7
- import { VisualizerTimeline } from "../helpers/types";
8
- import { all, Color, createRef, waitFor } from "@revideo/core";
9
- import { addAudioElement, addCaptionElement, addCircleElement, addIconElement, addMediaElement, addRectElement, addTextElement, makeSceneElements } from "./element";
10
- import { CAPTION_STYLE, DEFAULT_CAPTION_COLORS, DEFAULT_CAPTION_FONT, ELEMENT_TYPES } from "../helpers/constants";
11
- import { logger } from "../helpers/log.utils";
12
-
13
- /**
14
- * Creates a video timeline with specified configuration
15
- * @param {Object} params - Parameters for video timeline creation
16
- * @param {View2D} params.view - The 2D view to render the video in
17
- * @param {VideoTimeline} params.timeline - Video timeline configuration
18
- * @returns {Generator} Generator function for video timeline animation
19
- */
20
- export function* makeVideoTimeline({
21
- view,
22
- timeline,
23
- }: {
24
- view: View2D;
25
- timeline: VisualizerTimeline;
26
- }) {
27
- const frameRef = createRef<any>();
28
- let prevTime = 0;
29
- view.add(<Layout size={"100%"} ref={frameRef} layout />);
30
- for (const element of timeline.elements || []) {
31
- yield* waitFor(element?.s - prevTime);
32
- yield* addMediaElement({
33
- containerRef: frameRef,
34
- element,
35
- mediaType: ELEMENT_TYPES.VIDEO,
36
- waitOnStart: false,
37
- });
38
- prevTime = element.e;
39
- }
40
- yield frameRef().remove();
41
- }
42
-
43
- /**
44
- * Creates an audio timeline with specified configuration
45
- * @param {Object} params - Parameters for audio timeline creation
46
- * @param {View2D} params.view - The 2D view to render the audio in
47
- * @param {AudioTimeline} params.timeline - Audio timeline configuration
48
- * @returns {Generator} Generator function for audio timeline animation
49
- */
50
- export function* makeAudioTimeline({
51
- view,
52
- timeline,
53
- }: {
54
- view: View2D;
55
- timeline: VisualizerTimeline;
56
- }) {
57
- let prevTime = 0;
58
- for (const audioElement of timeline.elements) {
59
- const audioRef = createRef<any>();
60
- yield* waitFor(audioElement?.s - prevTime);
61
- prevTime = audioElement?.e;
62
- logger(`Adding audio element ${audioElement.id}`);
63
- view.add(
64
- <Audio ref={audioRef} key={audioElement.id} {...audioElement.props} />
65
- );
66
- yield* waitFor(Math.max(0, audioElement.e - audioElement.s));
67
- yield audioRef().playing(false);
68
- yield audioRef().remove();
69
- }
70
- }
71
-
72
- /**
73
- * Creates a caption timeline with specified configuration
74
- * @param {Object} params - Parameters for caption timeline creation
75
- * @param {View2D} params.view - The 2D view to render the caption in
76
- * @param {CaptionTimeline} params.timeline - Caption timeline configuration
77
- * @returns {Generator} Generator function for caption timeline animation
78
- */
79
- export function* makeCaptionTimeline({ view, timeline }: { view: View2D; timeline: VisualizerTimeline }) {
80
- let prevTime = 0;
81
- const captionTimelineRef = createRef<any>();
82
- view.add(<Layout size={"100%"} ref={captionTimelineRef} />);
83
-
84
- const tProps = timeline?.props;
85
-
86
- const timelineDefaultProps = (CAPTION_STYLE[tProps?.capStyle ?? ""] || {}).word || {};
87
-
88
- for (const element of timeline.elements) {
89
- const eProps = element.props;
90
- const rectStyle = (CAPTION_STYLE[eProps?.capStyle ?? tProps?.capStyle ?? ""] || {}).rect || {};
91
- // Cast alignItems/justifyContent as any to satisfy RectProps
92
- const mappedRectStyle = {
93
- ...rectStyle,
94
- justifyContent: rectStyle.justifyContent as any,
95
- alignItems: rectStyle.alignItems as any,
96
- };
97
- const phraseProps = {
98
- ...timelineDefaultProps,
99
- colors: {
100
- text: eProps?.colors?.text ?? tProps?.colors?.text ?? DEFAULT_CAPTION_COLORS.text,
101
- background: eProps?.colors?.background ?? tProps?.colors?.background ?? DEFAULT_CAPTION_COLORS.background,
102
- },
103
- font: {
104
- family: eProps?.font?.family ?? tProps?.font?.family ?? DEFAULT_CAPTION_FONT.family,
105
- size: eProps?.font?.size ?? tProps?.font?.size ?? DEFAULT_CAPTION_FONT.size,
106
- weight: eProps?.font?.weight ?? tProps?.font?.weight ?? DEFAULT_CAPTION_FONT.weight
107
- },
108
- fill: eProps?.colors?.text ?? tProps?.colors?.text ?? DEFAULT_CAPTION_COLORS.text,
109
- bgColor: eProps?.colors?.background ?? tProps?.colors?.background ??DEFAULT_CAPTION_COLORS.background,
110
- bgOpacity: eProps?.bgOpacity ?? tProps?.bgOpacity ?? 1,
111
- ...(tProps?.captionProps || {}),
112
- };
113
-
114
- yield* waitFor(element?.s - prevTime);
115
- const phraseRef = createRef<any>();
116
- captionTimelineRef().add(
117
- <Rect
118
- ref={phraseRef}
119
- key={element.id}
120
- {...mappedRectStyle}
121
- x={eProps?.x ?? tProps?.x}
122
- y={eProps?.y ?? tProps?.y}
123
- layout
124
- />
125
- );
126
- if (tProps?.capStyle === "word_by_word_with_bg") {
127
- phraseRef().fill(
128
- new Color(phraseProps.bgColor).alpha(phraseProps.bgOpacity)
129
- );
130
- }
131
- yield* addCaptionElement({
132
- caption: {...element, t: element.t ?? ""},
133
- captionProps: phraseProps,
134
- containerRef: phraseRef,
135
- capStyle: eProps?.capStyle ?? tProps?.capStyle,
136
- });
137
- prevTime = element.e;
138
- yield phraseRef().remove();
139
- }
140
- }
141
-
142
- /**
143
- * Creates a scene timeline with specified configuration
144
- * @param {Object} params - Parameters for scene timeline creation
145
- * @param {View2D} params.view - The 2D view to render the scene in
146
- * @param {SceneTimeline} params.timeline - Scene timeline configuration
147
- * @returns {Generator} Generator function for scene timeline animation
148
- */
149
- export function* makeSceneTimeline({ view, timeline }: { view: View2D; timeline: VisualizerTimeline }) {
150
- const frameRef = createRef<any>();
151
- let prevTime = 0;
152
- view.add(<Layout size={"100%"} ref={frameRef} layout />);
153
- for (const sceneElement of timeline.elements || []) {
154
- yield* waitFor(sceneElement?.s - prevTime);
155
- yield* makeSceneElements({
156
- containerRef: frameRef,
157
- element: sceneElement,
158
- });
159
- prevTime = sceneElement.e;
160
- }
161
- yield frameRef().remove();
162
- }
163
-
164
- /**
165
- * Creates an element timeline with specified configuration
166
- * @param {Object} params - Parameters for element timeline creation
167
- * @param {View2D} params.view - The 2D view to render the element in
168
- * @param {ElementTimeline} params.timeline - Element timeline configuration
169
- * @returns {Generator} Generator function for element timeline animation
170
- */
171
- export function* makeElementTimeline({ view, timeline }: { view: View2D; timeline: VisualizerTimeline }) {
172
- const elementTimelineRef = createRef<any>();
173
- view.add(<Layout size={"100%"} ref={elementTimelineRef} />);
174
-
175
- const sequence = [];
176
- for (const element of timeline.elements) {
177
- switch (element.type) {
178
- case ELEMENT_TYPES.RECT:
179
- sequence.push(
180
- addRectElement({ containerRef: elementTimelineRef, element })
181
- );
182
- break;
183
- case ELEMENT_TYPES.TEXT:
184
- sequence.push(
185
- addTextElement({ containerRef: elementTimelineRef, element })
186
- );
187
- break;
188
- case ELEMENT_TYPES.IMAGE:
189
- sequence.push(
190
- addMediaElement({
191
- containerRef: elementTimelineRef,
192
- element,
193
- mediaType: ELEMENT_TYPES.IMAGE,
194
- })
195
- );
196
- break;
197
- case ELEMENT_TYPES.VIDEO:
198
- sequence.push(
199
- addMediaElement({
200
- containerRef: elementTimelineRef,
201
- element,
202
- mediaType: ELEMENT_TYPES.VIDEO,
203
- })
204
- );
205
- break;
206
- case ELEMENT_TYPES.AUDIO:
207
- sequence.push(
208
- addAudioElement({ containerRef: elementTimelineRef, element })
209
- );
210
- break;
211
- case ELEMENT_TYPES.CIRCLE:
212
- sequence.push(
213
- addCircleElement({ containerRef: elementTimelineRef, element })
214
- );
215
- break;
216
- case ELEMENT_TYPES.ICON:
217
- sequence.push(
218
- addIconElement({ containerRef: elementTimelineRef, element })
219
- );
220
- break;
221
- }
222
- }
223
- yield* all(...sequence);
224
- yield elementTimelineRef().remove();
225
- }