3v324v23 commited on
Commit
bc18ad5
·
1 Parent(s): 892c4cc
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +7 -0
  2. Dockerfile +54 -0
  3. README.md +63 -10
  4. package.json +38 -0
  5. remotion/Root.tsx +96 -0
  6. remotion/index.tsx +8 -0
  7. src/player/animated/index.ts +3 -0
  8. src/player/animated/presets.ts +629 -0
  9. src/player/animated/text-animated-full.tsx +164 -0
  10. src/player/animated/text-animated-types/animations-in/background-in.tsx +71 -0
  11. src/player/animated/text-animated-types/animations-in/beatiful-question-in.tsx +49 -0
  12. src/player/animated/text-animated-types/animations-in/count-down-in.tsx +78 -0
  13. src/player/animated/text-animated-types/animations-in/descompress-in.tsx +36 -0
  14. src/player/animated/text-animated-types/animations-in/domino-dreams-in.tsx +43 -0
  15. src/player/animated/text-animated-types/animations-in/drop-in.tsx +36 -0
  16. src/player/animated/text-animated-types/animations-in/great-thinkers-in.tsx +43 -0
  17. src/player/animated/text-animated-types/animations-in/made-with-love-in.tsx +54 -0
  18. src/player/animated/text-animated-types/animations-in/reality-is-broken-in.tsx +71 -0
  19. src/player/animated/text-animated-types/animations-in/rising-strong-in.tsx +51 -0
  20. src/player/animated/text-animated-types/animations-in/sound-wave-in.tsx +150 -0
  21. src/player/animated/text-animated-types/animations-in/sunny-mornings-in.tsx +51 -0
  22. src/player/animated/text-animated-types/animations-in/text-animated-in.tsx +62 -0
  23. src/player/animated/text-animated-types/animations-in/type-writer-in.tsx +64 -0
  24. src/player/animated/text-animated-types/animations-loop/billboard.tsx +24 -0
  25. src/player/animated/text-animated-types/animations-loop/dragonfly.tsx +30 -0
  26. src/player/animated/text-animated-types/animations-loop/font-change.tsx +41 -0
  27. src/player/animated/text-animated-types/animations-loop/glitch.tsx +40 -0
  28. src/player/animated/text-animated-types/animations-loop/heartbeat.tsx +30 -0
  29. src/player/animated/text-animated-types/animations-loop/pulse.tsx +61 -0
  30. src/player/animated/text-animated-types/animations-loop/rotate-3d.tsx +49 -0
  31. src/player/animated/text-animated-types/animations-loop/shake-text.tsx +23 -0
  32. src/player/animated/text-animated-types/animations-loop/shaky-letters-text.tsx +33 -0
  33. src/player/animated/text-animated-types/animations-loop/spin.tsx +24 -0
  34. src/player/animated/text-animated-types/animations-loop/vintage.tsx +62 -0
  35. src/player/animated/text-animated-types/animations-loop/vogue.tsx +30 -0
  36. src/player/animated/text-animated-types/animations-loop/wave.tsx +26 -0
  37. src/player/animated/text-animated-types/animations-out/background-out.tsx +86 -0
  38. src/player/animated/text-animated-types/animations-out/beatiful-question-out.tsx +52 -0
  39. src/player/animated/text-animated-types/animations-out/descompress-out.tsx +41 -0
  40. src/player/animated/text-animated-types/animations-out/domino-dreams-out.tsx +47 -0
  41. src/player/animated/text-animated-types/animations-out/drop-out.tsx +42 -0
  42. src/player/animated/text-animated-types/animations-out/great-thinkers-out.tsx +46 -0
  43. src/player/animated/text-animated-types/animations-out/made-with-love-out.tsx +57 -0
  44. src/player/animated/text-animated-types/animations-out/reality-is-broken-out.tsx +69 -0
  45. src/player/animated/text-animated-types/animations-out/sunny-mornings-out.tsx +52 -0
  46. src/player/animated/text-animated-types/animations-out/text-animated-out.tsx +60 -0
  47. src/player/animated/text-animated-types/animations-out/type-writer-out.tsx +71 -0
  48. src/player/animated/text-animated.tsx +226 -0
  49. src/player/animated/types.ts +58 -0
  50. src/player/base-sequence.tsx +101 -0
.gitignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ node_modules/
2
+ dist/
3
+ videos/
4
+ jobs/
5
+ *.log
6
+ .env
7
+ .env.local
Dockerfile ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:20-slim
2
+
3
+ # Install FFmpeg and Chromium dependencies
4
+ RUN apt-get update && apt-get install -y \
5
+ ffmpeg \
6
+ chromium \
7
+ fonts-liberation \
8
+ libasound2 \
9
+ libatk-bridge2.0-0 \
10
+ libatk1.0-0 \
11
+ libatspi2.0-0 \
12
+ libcups2 \
13
+ libdbus-1-3 \
14
+ libdrm2 \
15
+ libgbm1 \
16
+ libgtk-3-0 \
17
+ libnspr4 \
18
+ libnss3 \
19
+ libxcomposite1 \
20
+ libxdamage1 \
21
+ libxfixes3 \
22
+ libxrandr2 \
23
+ xdg-utils \
24
+ && rm -rf /var/lib/apt/lists/*
25
+
26
+ # Set Chromium path for Puppeteer
27
+ ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
28
+
29
+ WORKDIR /app
30
+
31
+ # Copy package files
32
+ COPY package*.json ./
33
+
34
+ # Install dependencies
35
+ RUN npm install --production
36
+
37
+ # Copy source files
38
+ COPY . .
39
+
40
+ # Build TypeScript
41
+ RUN npm run build
42
+
43
+ # Create directories for videos and jobs
44
+ RUN mkdir -p videos jobs
45
+
46
+ # Expose port 7860 (Hugging Face default)
47
+ EXPOSE 7860
48
+
49
+ # Set environment variables
50
+ ENV PORT=7860
51
+ ENV NODE_ENV=production
52
+
53
+ # Start the server
54
+ CMD ["npm", "start"]
README.md CHANGED
@@ -1,10 +1,63 @@
1
- ---
2
- title: Veditor Render Server
3
- emoji:
4
- colorFrom: blue
5
- colorTo: red
6
- sdk: docker
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # VEditor Render Server
2
+
3
+ Standalone render server for video generation using Remotion.
4
+
5
+ ## Deploy to Hugging Face Spaces
6
+
7
+ 1. Create a new Space with "Docker" SDK
8
+ 2. Push this folder to the Space
9
+ 3. Wait for build to complete
10
+
11
+ ## API Endpoints
12
+
13
+ ### POST /render
14
+ Start a new render job.
15
+
16
+ **Request:**
17
+ ```json
18
+ {
19
+ "design": { ... },
20
+ "options": {
21
+ "fps": 30,
22
+ "width": 1920,
23
+ "height": 1080,
24
+ "format": "mp4"
25
+ }
26
+ }
27
+ ```
28
+
29
+ **Response:**
30
+ ```json
31
+ {
32
+ "jobId": "abc123",
33
+ "status": "pending"
34
+ }
35
+ ```
36
+
37
+ ### GET /render/:jobId
38
+ Check render status.
39
+
40
+ **Response:**
41
+ ```json
42
+ {
43
+ "jobId": "abc123",
44
+ "status": "completed",
45
+ "progress": 100,
46
+ "outputUrl": "/videos/abc123.mp4"
47
+ }
48
+ ```
49
+
50
+ ### GET /videos/:filename
51
+ Download rendered video.
52
+
53
+ ## Local Development
54
+
55
+ ```bash
56
+ npm install
57
+ npm run dev
58
+ ```
59
+
60
+ ## Environment Variables
61
+
62
+ - `PORT`: Server port (default: 7860)
63
+ - `CONCURRENCY`: Render threads (default: 4)
package.json ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "veditor-render-server",
3
+ "version": "1.0.0",
4
+ "description": "Standalone render server for VEditor using Remotion",
5
+ "main": "dist/server.js",
6
+ "scripts": {
7
+ "dev": "tsx watch src/server.ts",
8
+ "build": "tsc",
9
+ "start": "node dist/server.js",
10
+ "render": "tsx src/render.ts"
11
+ },
12
+ "dependencies": {
13
+ "@designcombo/events": "^0.0.1",
14
+ "@designcombo/state": "^0.0.1",
15
+ "@designcombo/transitions": "^0.0.1",
16
+ "@designcombo/types": "^0.0.1",
17
+ "@remotion/bundler": "4.0.407",
18
+ "@remotion/renderer": "4.0.407",
19
+ "cors": "^2.8.5",
20
+ "express": "^4.18.2",
21
+ "lodash": "^4.17.21",
22
+ "react": "^18.2.0",
23
+ "react-dom": "^18.2.0",
24
+ "remotion": "4.0.407",
25
+ "uuid": "^9.0.0",
26
+ "zustand": "^4.4.7"
27
+ },
28
+ "devDependencies": {
29
+ "@types/cors": "^2.8.17",
30
+ "@types/express": "^4.17.21",
31
+ "@types/lodash": "^4.14.202",
32
+ "@types/node": "^20.10.0",
33
+ "@types/react": "^18.2.43",
34
+ "@types/uuid": "^9.0.7",
35
+ "tsx": "^4.7.0",
36
+ "typescript": "^5.3.2"
37
+ }
38
+ }
remotion/Root.tsx ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Remotion Root - Entry point for Render Server
3
+ *
4
+ * Uses SSRComposition from the copied player folder.
5
+ */
6
+
7
+ import React from "react";
8
+ import { Composition } from "remotion";
9
+ import { SSRComposition } from "../../../src/player/ssr-composition";
10
+
11
+ // Default design types
12
+ interface IDesign {
13
+ id?: string;
14
+ size?: { width: number; height: number };
15
+ fps?: number;
16
+ trackItemIds?: string[];
17
+ trackItemsMap?: Record<string, unknown>;
18
+ tracks?: unknown[];
19
+ transitionIds?: string[];
20
+ transitionsMap?: Record<string, unknown>;
21
+ duration?: number;
22
+ background?: string | { value: string };
23
+ }
24
+
25
+ interface ITrackItem {
26
+ display?: { from: number; to: number };
27
+ }
28
+
29
+ // Default empty design
30
+ const defaultDesign: IDesign = {
31
+ id: "default",
32
+ size: { width: 1920, height: 1080 },
33
+ fps: 30,
34
+ trackItemIds: [],
35
+ trackItemsMap: {},
36
+ tracks: [],
37
+ transitionIds: [],
38
+ transitionsMap: {},
39
+ duration: 5000,
40
+ };
41
+
42
+ // Calculate actual duration from track items
43
+ const calculateDesignDuration = (design: IDesign): number => {
44
+ const trackItems = Object.values(design.trackItemsMap || {}) as ITrackItem[];
45
+
46
+ if (trackItems.length === 0) {
47
+ return design.duration || 5000;
48
+ }
49
+
50
+ const maxEndTime = Math.max(
51
+ ...trackItems.map(item => item.display?.to || 0)
52
+ );
53
+
54
+ return maxEndTime || design.duration || 5000;
55
+ };
56
+
57
+ export const RemotionRoot: React.FC = () => {
58
+ return (
59
+ <>
60
+ <Composition
61
+ id="VEditor"
62
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
+ component={SSRComposition as React.ComponentType<any>}
64
+ durationInFrames={150}
65
+ fps={30}
66
+ width={1920}
67
+ height={1080}
68
+ defaultProps={{
69
+ design: defaultDesign,
70
+ }}
71
+ calculateMetadata={async ({ props }) => {
72
+ const design = (props as { design: IDesign }).design;
73
+ const fps = design.fps || 30;
74
+
75
+ const durationMs = calculateDesignDuration(design);
76
+ const durationInFrames = Math.max(1, Math.ceil((durationMs / 1000) * fps));
77
+
78
+ console.log('[Remotion] Metadata:', {
79
+ durationMs,
80
+ durationInFrames,
81
+ fps,
82
+ width: design.size?.width || 1920,
83
+ height: design.size?.height || 1080,
84
+ });
85
+
86
+ return {
87
+ durationInFrames,
88
+ fps,
89
+ width: design.size?.width || 1920,
90
+ height: design.size?.height || 1080,
91
+ };
92
+ }}
93
+ />
94
+ </>
95
+ );
96
+ };
remotion/index.tsx ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Remotion Entry Point for Render Server
3
+ */
4
+
5
+ import { registerRoot } from 'remotion';
6
+ import { RemotionRoot } from './Root';
7
+
8
+ registerRoot(RemotionRoot);
src/player/animated/index.ts ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ export * from "./types";
2
+
3
+ export { presets } from "./presets";
src/player/animated/presets.ts ADDED
@@ -0,0 +1,629 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Easing } from "remotion";
2
+ import { Animation } from "./types";
3
+
4
+ // Define preset names
5
+ export type PresetName =
6
+ | "fadeIn"
7
+ | "fadeOut"
8
+ | "scaleIn"
9
+ | "scaleOut"
10
+ | "slideInRight"
11
+ | "slideInLeft"
12
+ | "slideInTop"
13
+ | "slideInBottom"
14
+ | "slideOutRight"
15
+ | "slideOutLeft"
16
+ | "slideOutTop"
17
+ | "slideOutBottom"
18
+ | "rotateIn"
19
+ | "flipIn"
20
+ | "shakeHorizontalIn"
21
+ | "shakeVerticalIn"
22
+ | "shakeHorizontalOut"
23
+ | "shakeVerticalOut"
24
+ | "typeWriterIn"
25
+ | "typeWriterOut"
26
+ | "animatedTextIn"
27
+ | "sunnyMorningsAnimationIn"
28
+ | "dominoDreamsIn"
29
+ // | "thursdayIn"
30
+ | "greatThinkersAnimationIn"
31
+ | "beautifulQuestionsAnimationIn"
32
+ | "madeWithLoveAnimationIn"
33
+ // | "risingStrongAnimationIn"
34
+ | "realityIsBrokenAnimationIn"
35
+ | "animatedTextOut"
36
+ | "sunnyMorningsAnimationOut"
37
+ | "dominoDreamsAnimationOut"
38
+ | "beautifulQuestionsAnimationOut"
39
+ | "madeWithLoveAnimationOut"
40
+ | "realityIsBrokenAnimationOut"
41
+ | "greatThinkersAnimationOut"
42
+ | "vogueAnimationLoop"
43
+ | "dragonFlyAnimationLoop"
44
+ | "billboardAnimationLoop"
45
+ | "descompressAnimationIn"
46
+ | "dropAnimationIn"
47
+ | "dropAnimationOut"
48
+ | "descompressAnimationOut"
49
+ | "heartbeatAnimationLoop"
50
+ | "spinAnimationLoop"
51
+ | "waveAnimationLoop"
52
+ | "rotate3dAnimationLoop"
53
+ | "shakeTextAnimationLoop"
54
+ | "shakyLettersTextAnimationLoop"
55
+ | "vintageAnimationLoop"
56
+ | "textFontChangeAnimationLoop"
57
+ | "pulseAnimationLoop"
58
+ | "glitchAnimationLoop"
59
+ | "countDownAnimationIn"
60
+ | "soundWaveIn"
61
+ | "backgroundAnimationOut"
62
+ | "backgroundAnimationIn";
63
+
64
+ // Type-safe preset object
65
+ export const presets: Record<PresetName, Animation> = {
66
+ pulseAnimationLoop: {
67
+ property: "pulseTextAnimationLoop",
68
+ from: 0,
69
+ to: 1,
70
+ durationInFrames: 30,
71
+ ease: Easing.linear,
72
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
73
+ name: "Pulse Animation Loop"
74
+ },
75
+ glitchAnimationLoop: {
76
+ property: "glitchTextAnimationLoop",
77
+ from: 0,
78
+ to: 1,
79
+ durationInFrames: 30,
80
+ ease: Easing.linear,
81
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
82
+ name: "Glitch Animation Loop"
83
+ },
84
+ countDownAnimationIn: {
85
+ property: "countDownTextAnimationIn",
86
+ from: 0,
87
+ to: 1,
88
+ durationInFrames: 30,
89
+ ease: Easing.linear,
90
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
91
+ name: "Count Down Animation In"
92
+ },
93
+ soundWaveIn: {
94
+ property: "soundWaveTextAnimationIn",
95
+ from: 0,
96
+ to: 1,
97
+ durationInFrames: 30,
98
+ ease: Easing.linear,
99
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
100
+ name: "Sound Wave Animation In"
101
+ },
102
+ backgroundAnimationOut: {
103
+ property: "backgroundTextAnimationOut",
104
+ from: 0,
105
+ to: 1,
106
+ durationInFrames: 30,
107
+ ease: Easing.linear,
108
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
109
+ name: "Background Animation Out"
110
+ },
111
+ backgroundAnimationIn: {
112
+ property: "backgroundTextAnimationIn",
113
+ from: 0,
114
+ to: 1,
115
+ durationInFrames: 30,
116
+ ease: Easing.linear,
117
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
118
+ name: "Background Animation In"
119
+ },
120
+ textFontChangeAnimationLoop: {
121
+ property: "textFontChangeAnimationLoop",
122
+ from: 0,
123
+ to: 1,
124
+ durationInFrames: 30,
125
+ ease: Easing.linear,
126
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
127
+ name: "Font Change Animation Loop",
128
+ details: {
129
+ fonts: [
130
+ {
131
+ fontFamily: "Bangers-Regular",
132
+ url: "https://fonts.gstatic.com/s/bangers/v13/FeVQS0BTqb0h60ACL5la2bxii28.ttf"
133
+ },
134
+ {
135
+ fontFamily: "AnonymousPro-BoldItalic",
136
+ url: "https://fonts.gstatic.com/s/anonymouspro/v14/rP2ap2a15UIB7Un-bOeISG3pHl4OTCzc6IG30KqB9Q.ttf"
137
+ },
138
+ {
139
+ fontFamily: "Frijole",
140
+ url: "https://fonts.gstatic.com/s/frijole/v9/uU9PCBUR8oakM2BQ7xPb3vyHmlI.ttf"
141
+ },
142
+ {
143
+ fontFamily: "Bangers-Regular",
144
+ url: "https://fonts.gstatic.com/s/bangers/v13/FeVQS0BTqb0h60ACL5la2bxii28.ttf"
145
+ },
146
+ {
147
+ fontFamily: "Allura-Regular",
148
+ url: "https://fonts.gstatic.com/s/allura/v15/9oRPNYsQpS4zjuAPjAIXPtrrGA.ttf"
149
+ }
150
+ ]
151
+ }
152
+ },
153
+ vintageAnimationLoop: {
154
+ property: "vintageTextAnimationLoop",
155
+ from: 0,
156
+ to: 1,
157
+ durationInFrames: 30,
158
+ ease: Easing.linear,
159
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
160
+ name: "Vintage Animation Loop"
161
+ },
162
+ shakyLettersTextAnimationLoop: {
163
+ property: "shakyLettersTextAnimationLoop",
164
+ from: 0,
165
+ to: 1,
166
+ durationInFrames: 30,
167
+ ease: Easing.linear,
168
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
169
+ name: "Shaky Letters Animation Loop"
170
+ },
171
+ shakeTextAnimationLoop: {
172
+ property: "shakeTextAnimationLoop",
173
+ from: 0,
174
+ to: 1,
175
+ durationInFrames: 30,
176
+ ease: Easing.linear,
177
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
178
+ name: "Shake Text Animation Loop"
179
+ },
180
+ rotate3dAnimationLoop: {
181
+ property: "rotate3dTextAnimationLoop",
182
+ from: 0,
183
+ to: 360,
184
+ durationInFrames: 30,
185
+ ease: Easing.linear,
186
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
187
+ name: "Rotate 3D Animation Loop"
188
+ },
189
+ heartbeatAnimationLoop: {
190
+ property: "heartbeatTextAnimationLoop",
191
+ from: 0,
192
+ to: 1,
193
+ durationInFrames: 30,
194
+ ease: Easing.linear,
195
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
196
+ name: "Heartbeat Animation Loop"
197
+ },
198
+ spinAnimationLoop: {
199
+ property: "spinTextAnimationLoop",
200
+ from: 0,
201
+ to: 1,
202
+ durationInFrames: 30,
203
+ ease: Easing.linear,
204
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
205
+ name: "Spin Animation Loop"
206
+ },
207
+ waveAnimationLoop: {
208
+ property: "waveTextAnimationLoop",
209
+ from: 0,
210
+ to: 1,
211
+ durationInFrames: 30,
212
+ ease: Easing.linear,
213
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
214
+ name: "Wave Animation Loop"
215
+ },
216
+ descompressAnimationIn: {
217
+ property: "descompressTextAnimationIn",
218
+ from: 0,
219
+ to: 1,
220
+ durationInFrames: 30,
221
+ ease: Easing.linear,
222
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
223
+ name: "Descompress Animation In"
224
+ },
225
+ dropAnimationIn: {
226
+ property: "dropTextAnimationIn",
227
+ from: 0,
228
+ to: 1,
229
+ durationInFrames: 30,
230
+ ease: Easing.linear,
231
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
232
+ name: "Drop Animation In"
233
+ },
234
+ dropAnimationOut: {
235
+ property: "dropTextAnimationOut",
236
+ from: 0,
237
+ to: 1,
238
+ durationInFrames: 30,
239
+ ease: Easing.linear,
240
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
241
+ name: "Drop Animation Out"
242
+ },
243
+ descompressAnimationOut: {
244
+ property: "descompressTextAnimationOut",
245
+ from: 0,
246
+ to: 1,
247
+ durationInFrames: 30,
248
+ ease: Easing.linear,
249
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
250
+ name: "Descompress Animation Out"
251
+ },
252
+ vogueAnimationLoop: {
253
+ property: "vogueTextAnimationLoop",
254
+ from: 0,
255
+ to: 1,
256
+ durationInFrames: 30,
257
+ ease: Easing.linear,
258
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
259
+ name: "Vogue Animation Loop"
260
+ },
261
+ dragonFlyAnimationLoop: {
262
+ property: "dragonFlyTextAnimationLoop",
263
+ from: 0,
264
+ to: 1,
265
+ durationInFrames: 30,
266
+ ease: Easing.linear,
267
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
268
+ name: "Dragon Fly Animation Loop"
269
+ },
270
+ billboardAnimationLoop: {
271
+ property: "billboardTextAnimationLoop",
272
+ from: 0,
273
+ to: 1,
274
+ durationInFrames: 30,
275
+ ease: Easing.linear,
276
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
277
+ name: "Billboard Animation Loop"
278
+ },
279
+ typeWriterOut: {
280
+ property: "typeWriterTextAnimationOut",
281
+ from: 0,
282
+ to: 1,
283
+ durationInFrames: 30,
284
+ ease: Easing.linear,
285
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
286
+ name: "Type Writer"
287
+ },
288
+ greatThinkersAnimationOut: {
289
+ property: "greatThinkersTextAnimationOut",
290
+ from: 0,
291
+ to: 1,
292
+ durationInFrames: 30,
293
+ ease: Easing.linear,
294
+ previewUrl: "https://cdn.designcombo.dev/animations/great-thinker-out.webp",
295
+ name: "Great Thinkers"
296
+ },
297
+ realityIsBrokenAnimationOut: {
298
+ property: "realityIsBrokenTextAnimationOut",
299
+ from: 0,
300
+ to: 1,
301
+ durationInFrames: 30,
302
+ ease: Easing.linear,
303
+ previewUrl:
304
+ "https://cdn.designcombo.dev/animations/realisty-is-broken-out.webp",
305
+ name: "Reality is Broken"
306
+ },
307
+ madeWithLoveAnimationOut: {
308
+ property: "madeWithLoveTextAnimationOut",
309
+ from: 0,
310
+ to: 1,
311
+ durationInFrames: 30,
312
+ ease: Easing.linear,
313
+ previewUrl:
314
+ "https://cdn.designcombo.dev/animations/made-with-love-out.webp",
315
+ name: "Made With Love"
316
+ },
317
+ realityIsBrokenAnimationIn: {
318
+ property: "realityIsBrokenTextAnimationIn",
319
+ from: 0,
320
+ to: 1,
321
+ durationInFrames: 30,
322
+ ease: Easing.linear,
323
+ previewUrl:
324
+ "https://cdn.designcombo.dev/animations/reality-is-broken-in.webp",
325
+ name: "Reality is Broken"
326
+ },
327
+ beautifulQuestionsAnimationOut: {
328
+ property: "beautifulQuestionsTextAnimationOut",
329
+ from: 0,
330
+ to: 1,
331
+ durationInFrames: 30,
332
+ ease: Easing.linear,
333
+ previewUrl:
334
+ "https://cdn.designcombo.dev/animations/beatiful-question-out.webp",
335
+ name: "Beautiful Questions"
336
+ },
337
+ animatedTextOut: {
338
+ property: "animatedTextOut",
339
+ from: 0,
340
+ to: 1,
341
+ durationInFrames: 30,
342
+ ease: Easing.linear,
343
+ previewUrl: "https://cdn.designcombo.dev/animations/animated-text-out.webp",
344
+ name: "Animated Text"
345
+ },
346
+ sunnyMorningsAnimationOut: {
347
+ property: "sunnyMorningsTextAnimationOut",
348
+ from: 0,
349
+ to: 1,
350
+ durationInFrames: 30,
351
+ ease: Easing.linear,
352
+ previewUrl:
353
+ "https://cdn.designcombo.dev/animations/sunny-mornings-out.webp",
354
+ name: "Sunny Mornings"
355
+ },
356
+ dominoDreamsAnimationOut: {
357
+ property: "dominoDreamsTextAnimationOut",
358
+ from: 0,
359
+ to: 1,
360
+ durationInFrames: 30,
361
+ ease: Easing.linear,
362
+ previewUrl: "https://cdn.designcombo.dev/animations/domino-dreams-out.webp",
363
+ name: "Domino Dreams"
364
+ },
365
+ madeWithLoveAnimationIn: {
366
+ property: "madeWithLoveTextAnimationIn",
367
+ from: 0,
368
+ to: 1,
369
+ durationInFrames: 30,
370
+ ease: Easing.linear,
371
+ previewUrl: "https://cdn.designcombo.dev/animations/made-with-love-in.webp",
372
+ name: "Made With Love"
373
+ },
374
+ beautifulQuestionsAnimationIn: {
375
+ property: "beautifulQuestionsTextAnimationIn",
376
+ from: 0,
377
+ to: 1,
378
+ durationInFrames: 30,
379
+ ease: Easing.linear,
380
+ previewUrl:
381
+ "https://cdn.designcombo.dev/animations/beautiful-questions-in.webp",
382
+ name: "Beatiful Questions"
383
+ },
384
+ greatThinkersAnimationIn: {
385
+ property: "greatThinkersTextAnimationIn",
386
+ from: 0,
387
+ to: 1,
388
+ durationInFrames: 30,
389
+ ease: Easing.linear,
390
+ previewUrl: "https://cdn.designcombo.dev/animations/great-thinker-in.webp",
391
+ name: "Great Thinkers"
392
+ },
393
+ // thursdayIn: {
394
+ // property: "textThursday",
395
+ // from: 0,
396
+ // to: 1,
397
+ // durationInFrames: 30,
398
+ // ease: Easing.linear,
399
+ // previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
400
+ // name: "TextThursday"
401
+ // },
402
+ dominoDreamsIn: {
403
+ property: "dominoDreamsTextAnimationIn",
404
+ from: 0,
405
+ to: 1,
406
+ durationInFrames: 30,
407
+ ease: Easing.linear,
408
+ previewUrl: "https://cdn.designcombo.dev/animations/domino-dreams-in.webp",
409
+ name: "Domino Dreams"
410
+ },
411
+ typeWriterIn: {
412
+ property: "typeWriterTextAnimationIn",
413
+ from: 0,
414
+ to: 1,
415
+ durationInFrames: 30,
416
+ ease: Easing.linear,
417
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
418
+ name: "Type Writer"
419
+ },
420
+ animatedTextIn: {
421
+ property: "animatedTextIn",
422
+ from: 0,
423
+ to: 1,
424
+ durationInFrames: 30,
425
+ ease: Easing.linear,
426
+ previewUrl: "https://cdn.designcombo.dev/animations/animated-text-in.webp",
427
+ name: "Animated Text"
428
+ },
429
+ sunnyMorningsAnimationIn: {
430
+ property: "sunnyMorningsTextAnimationIn",
431
+ from: 0,
432
+ to: 1,
433
+ durationInFrames: 30,
434
+ ease: Easing.linear,
435
+ previewUrl: "https://cdn.designcombo.dev/animations/sunny-mornings-in.webp",
436
+ name: "Sunny Mornings"
437
+ },
438
+ shakeHorizontalOut: {
439
+ property: "shakeHorizontalOut",
440
+ from: 0,
441
+ to: -0,
442
+ durationInFrames: 30,
443
+ ease: Easing.elastic(1),
444
+ previewUrl:
445
+ "https://cdn.designcombo.dev/animations/ShakeHorizontalOut.webp",
446
+ name: "Shake Horizontal"
447
+ },
448
+
449
+ shakeVerticalOut: {
450
+ property: "shakeVerticalOut",
451
+ from: 0,
452
+ to: -0,
453
+ durationInFrames: 30,
454
+ ease: Easing.elastic(1),
455
+ previewUrl: "https://cdn.designcombo.dev/animations/ShakeVerticalOut.webp",
456
+ name: "Shake Vertical"
457
+ },
458
+
459
+ shakeHorizontalIn: {
460
+ property: "shakeHorizontalIn",
461
+ from: 0,
462
+ to: -0,
463
+ durationInFrames: 30,
464
+ ease: Easing.elastic(1),
465
+ previewUrl: "https://cdn.designcombo.dev/animations/ShakeHorizontalIn.webp",
466
+ name: "Shake Horizontal"
467
+ },
468
+
469
+ shakeVerticalIn: {
470
+ property: "shakeVerticalIn",
471
+ from: 0,
472
+ to: -0,
473
+ durationInFrames: 30,
474
+ ease: Easing.elastic(1),
475
+ previewUrl: "https://cdn.designcombo.dev/animations/ShakeVerticalIn.webp",
476
+ name: "Shake Vertical"
477
+ },
478
+
479
+ rotateIn: {
480
+ property: "rotate",
481
+ from: 0,
482
+ to: 360,
483
+ durationInFrames: 30,
484
+ ease: Easing.linear,
485
+ previewUrl: "https://cdn.designcombo.dev/animations/scaleAndRotate.webp",
486
+ name: "Rotate"
487
+ },
488
+
489
+ flipIn: {
490
+ property: "rotateY",
491
+ from: -90,
492
+ to: 0,
493
+ durationInFrames: 30,
494
+ ease: Easing.linear,
495
+ previewUrl: "https://cdn.designcombo.dev/animations/flipIn.webp",
496
+ name: "Flip"
497
+ },
498
+
499
+ fadeIn: {
500
+ property: "opacity",
501
+ from: 0,
502
+ to: 1,
503
+ durationInFrames: 15,
504
+ ease: Easing.linear,
505
+ previewUrl: "https://cdn.designcombo.dev/animations/FadeIn.webp",
506
+ name: "Fade"
507
+ },
508
+
509
+ fadeOut: {
510
+ property: "opacity",
511
+ from: 1,
512
+ to: 0,
513
+ durationInFrames: 15,
514
+ ease: Easing.linear,
515
+ previewUrl: "https://cdn.designcombo.dev/animations/FadeOut.webp",
516
+ name: "Fade"
517
+ },
518
+
519
+ scaleIn: {
520
+ property: "scale",
521
+ from: 0,
522
+ to: 1,
523
+ durationInFrames: 15,
524
+ ease: Easing.ease,
525
+ previewUrl: "https://cdn.designcombo.dev/animations/ScaleIn.webp",
526
+ name: "Scale"
527
+ },
528
+
529
+ scaleOut: {
530
+ property: "scale",
531
+ from: 1,
532
+ to: 0,
533
+ durationInFrames: 15,
534
+ ease: Easing.ease,
535
+ previewUrl: "https://cdn.designcombo.dev/animations/ScaleOut.webp",
536
+ name: "Scale"
537
+ },
538
+
539
+ slideInRight: {
540
+ property: "translateX",
541
+ from: -900,
542
+ to: 0,
543
+ durationInFrames: 15,
544
+ delay: 0,
545
+ ease: Easing.ease,
546
+ previewUrl: "https://cdn.designcombo.dev/animations/SlideInRight.webp",
547
+ name: "Slide Right"
548
+ },
549
+
550
+ slideInLeft: {
551
+ property: "translateX",
552
+ from: 900,
553
+ to: 0,
554
+ durationInFrames: 15,
555
+ delay: 0,
556
+ ease: Easing.ease,
557
+ previewUrl: "https://cdn.designcombo.dev/animations/SlideInLeft.webp",
558
+ name: "Slide Left"
559
+ },
560
+
561
+ slideInTop: {
562
+ property: "translateY",
563
+ from: 900,
564
+ to: 0,
565
+ durationInFrames: 15,
566
+ delay: 0,
567
+ ease: Easing.ease,
568
+ previewUrl: "https://cdn.designcombo.dev/animations/SlideInTop.webp",
569
+ name: "Slide Top"
570
+ },
571
+
572
+ slideInBottom: {
573
+ property: "translateY",
574
+ from: -900,
575
+ to: 0,
576
+ durationInFrames: 15,
577
+ delay: 0,
578
+ ease: Easing.ease,
579
+ previewUrl: "https://cdn.designcombo.dev/animations/SlideInBottom.webp",
580
+ name: "Slide Bottom"
581
+ },
582
+
583
+ slideOutRight: {
584
+ property: "translateX",
585
+ from: 0,
586
+ to: -50,
587
+ durationInFrames: 15,
588
+ delay: 0,
589
+ ease: Easing.ease,
590
+ previewUrl: "https://cdn.designcombo.dev/animations/SlideOutRight.webp",
591
+ name: "Slide Right"
592
+ },
593
+
594
+ slideOutLeft: {
595
+ property: "translateX",
596
+ from: 0,
597
+ to: 50,
598
+ durationInFrames: 15,
599
+ delay: 0,
600
+ ease: Easing.ease,
601
+ previewUrl: "https://cdn.designcombo.dev/animations/SlideOutLeft.webp",
602
+ name: "Slide Left"
603
+ },
604
+
605
+ slideOutTop: {
606
+ property: "translateY",
607
+ from: 0,
608
+ to: 50,
609
+ durationInFrames: 15,
610
+ delay: 0,
611
+ ease: Easing.ease,
612
+ previewUrl: "https://cdn.designcombo.dev/animations/SlideOutUp.webp",
613
+ name: "Slide Top"
614
+ },
615
+
616
+ slideOutBottom: {
617
+ property: "translateY",
618
+ from: 0,
619
+ to: -50,
620
+ durationInFrames: 15,
621
+ delay: 0,
622
+ ease: Easing.ease,
623
+ previewUrl: "https://cdn.designcombo.dev/animations/slideOutDown.webp",
624
+ name: "Slide Bottom"
625
+ }
626
+ } as const;
627
+
628
+ // Export type for external usage
629
+ export type AnimationPresets = typeof presets;
src/player/animated/text-animated-full.tsx ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ITextDetails } from "@designcombo/types";
2
+ import TypeWriterIn from "./text-animated-types/animations-in/type-writer-in";
3
+ import TypeWriterOut from "./text-animated-types/animations-out/type-writer-out";
4
+ import BackgroundIn from "./text-animated-types/animations-in/background-in";
5
+ import BackgroundOut from "./text-animated-types/animations-out/background-out";
6
+ import SoundWaveIn from "./text-animated-types/animations-in/sound-wave-in";
7
+ import CountDownIn from "./text-animated-types/animations-in/count-down-in";
8
+ import Spin from "./text-animated-types/animations-loop/spin";
9
+ import Rotate3d from "./text-animated-types/animations-loop/rotate-3d";
10
+ import FontChange from "./text-animated-types/animations-loop/font-change";
11
+ import ShakeText from "./text-animated-types/animations-loop/shake-text";
12
+ import Vintage from "./text-animated-types/animations-loop/vintage";
13
+ import GlitchText from "./text-animated-types/animations-loop/glitch";
14
+ import { JSX } from "react";
15
+
16
+ type FullTextAnimationProps = {
17
+ frame: number;
18
+ text: string;
19
+ details: ITextDetails;
20
+ fps: number;
21
+ durationInFrames: number;
22
+ animationTextInFrames: number;
23
+ animationTextOutFrames: number;
24
+ animationTextLoopFrames: number;
25
+ animationFonts: { fontFamily: string; url: string }[];
26
+ validAnimIn: boolean;
27
+ validAnimOut: boolean;
28
+ textAnimationNameIn: string;
29
+ textAnimationNameOut: string;
30
+ textAnimationNameLoop: string;
31
+ };
32
+
33
+ export const renderFullTextAnimation = ({
34
+ frame,
35
+ text,
36
+ details,
37
+ fps,
38
+ durationInFrames,
39
+ animationTextInFrames,
40
+ animationTextOutFrames,
41
+ animationFonts,
42
+ validAnimIn,
43
+ validAnimOut,
44
+ textAnimationNameIn,
45
+ textAnimationNameOut,
46
+ textAnimationNameLoop
47
+ }: FullTextAnimationProps): JSX.Element | null => {
48
+ // Animaciones de entrada
49
+ if (validAnimIn) {
50
+ if (textAnimationNameIn === "typeWriterIn") {
51
+ return (
52
+ <TypeWriterIn
53
+ frame={frame}
54
+ durationInFrames={animationTextInFrames}
55
+ text={text}
56
+ style={details}
57
+ />
58
+ );
59
+ }
60
+
61
+ if (textAnimationNameIn === "backgroundAnimationIn") {
62
+ return (
63
+ <BackgroundIn
64
+ text={text}
65
+ frame={frame}
66
+ details={details}
67
+ animationTextInFrames={animationTextInFrames}
68
+ />
69
+ );
70
+ }
71
+
72
+ if (textAnimationNameIn === "soundWaveIn") {
73
+ return (
74
+ <SoundWaveIn
75
+ text={text}
76
+ frame={frame}
77
+ animationTextInFrames={animationTextInFrames}
78
+ details={details}
79
+ />
80
+ );
81
+ }
82
+
83
+ if (textAnimationNameIn === "countDownAnimationIn") {
84
+ return (
85
+ <CountDownIn
86
+ text={text}
87
+ frame={frame}
88
+ animationTextInFrames={animationTextInFrames}
89
+ details={details}
90
+ />
91
+ );
92
+ }
93
+ }
94
+
95
+ // Animaciones de salida
96
+ if (validAnimOut) {
97
+ if (textAnimationNameOut === "typeWriterOut") {
98
+ return (
99
+ <TypeWriterOut
100
+ frame={frame}
101
+ durationInFrames={durationInFrames}
102
+ text={text}
103
+ details={details}
104
+ animationDuration={animationTextOutFrames}
105
+ />
106
+ );
107
+ }
108
+
109
+ if (textAnimationNameOut === "backgroundAnimationOut") {
110
+ return (
111
+ <BackgroundOut
112
+ text={text}
113
+ frame={frame}
114
+ animationTextOutFrames={animationTextOutFrames}
115
+ details={details}
116
+ durationInFrames={durationInFrames}
117
+ fps={fps}
118
+ />
119
+ );
120
+ }
121
+ }
122
+
123
+ // Animaciones en bucle
124
+ if (!validAnimIn && !validAnimOut) {
125
+ if (textAnimationNameLoop === "spinAnimationLoop") {
126
+ return <Spin text={text} frame={frame} fps={fps} />;
127
+ }
128
+
129
+ if (textAnimationNameLoop === "rotate3dAnimationLoop") {
130
+ return (
131
+ <Rotate3d
132
+ text={text}
133
+ frame={frame}
134
+ durationInFrames={durationInFrames}
135
+ />
136
+ );
137
+ }
138
+
139
+ if (textAnimationNameLoop === "textFontChangeAnimationLoop") {
140
+ return (
141
+ <FontChange
142
+ text={text}
143
+ frame={frame}
144
+ details={details}
145
+ animationFonts={animationFonts}
146
+ />
147
+ );
148
+ }
149
+
150
+ if (textAnimationNameLoop === "shakeTextAnimationLoop") {
151
+ return <ShakeText text={text} frame={frame} />;
152
+ }
153
+
154
+ if (textAnimationNameLoop === "vintageAnimationLoop") {
155
+ return <Vintage text={text} frame={frame} details={details} fps={fps} />;
156
+ }
157
+
158
+ if (textAnimationNameLoop === "glitchAnimationLoop") {
159
+ return <GlitchText text={text} frame={frame} />;
160
+ }
161
+ }
162
+
163
+ return null;
164
+ };
src/player/animated/text-animated-types/animations-in/background-in.tsx ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ITextDetails } from "@designcombo/types";
2
+ import { interpolate } from "remotion";
3
+
4
+ const BackgroundIn = ({
5
+ text,
6
+ frame,
7
+ details,
8
+ animationTextInFrames
9
+ }: {
10
+ text: string;
11
+ frame: number;
12
+ details: ITextDetails;
13
+ animationTextInFrames: number;
14
+ }) => {
15
+ const progress = interpolate(frame, [0, animationTextInFrames], [0, 1], {
16
+ extrapolateRight: "clamp"
17
+ });
18
+ const fullWidth = details.width;
19
+ const fullHeight = details.height;
20
+
21
+ const revealWidth = interpolate(progress, [0, 1], [0, fullWidth]);
22
+ const textTranslateX = interpolate(progress, [0, 1], [fullWidth / 2, 0]);
23
+
24
+ return (
25
+ <div
26
+ style={{
27
+ flex: 1,
28
+ position: "relative",
29
+ justifyContent: "flex-start",
30
+ alignItems: "center",
31
+ display: "flex",
32
+ width: details.width,
33
+ height: details.height
34
+ }}
35
+ >
36
+ <div
37
+ style={{
38
+ width: revealWidth,
39
+ height: fullHeight,
40
+ overflow: "hidden",
41
+ display: "flex",
42
+ position: "relative",
43
+ alignItems: "center",
44
+ justifyContent: "center",
45
+ backgroundColor: "white"
46
+ }}
47
+ >
48
+ <div
49
+ style={{
50
+ fontSize: parseFloat(details.fontSize.toString()),
51
+ display: "flex",
52
+ position: "absolute",
53
+ justifyContent: "center",
54
+ alignItems: "center",
55
+ width: details.width,
56
+ height: details.height,
57
+ color:
58
+ details.color === "white" || details.color.includes("fff")
59
+ ? "black"
60
+ : details.color,
61
+ transform: `translateX(${textTranslateX * 2}px)`
62
+ }}
63
+ >
64
+ {text}
65
+ </div>
66
+ </div>
67
+ </div>
68
+ );
69
+ };
70
+
71
+ export default BackgroundIn;
src/player/animated/text-animated-types/animations-in/beatiful-question-in.tsx ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { interpolate, spring } from "remotion";
2
+
3
+ const BeatifulQuestionAnimationIn = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextInFrames
10
+ }: {
11
+ char: string;
12
+ index: number;
13
+ frame: number;
14
+ fps: number;
15
+ textLength: number;
16
+ animationTextInFrames: number;
17
+ }) => {
18
+ const totalDuration = animationTextInFrames;
19
+ const delayFactor = totalDuration / textLength;
20
+ const delay = index * delayFactor;
21
+
22
+ const translateY = spring({
23
+ frame: frame - delay,
24
+ fps,
25
+ from: 1.1,
26
+ to: 0,
27
+ config: { damping: 10 }
28
+ });
29
+
30
+ const opacity = interpolate(frame - delay, [0, totalDuration / 2], [0, 1], {
31
+ extrapolateRight: "clamp",
32
+ extrapolateLeft: "clamp"
33
+ });
34
+
35
+ return (
36
+ <span
37
+ key={index}
38
+ style={{
39
+ display: "inline-block",
40
+ transform: `translateY(${translateY}em)`,
41
+ opacity
42
+ }}
43
+ >
44
+ {char === " " ? " " : char}
45
+ </span>
46
+ );
47
+ };
48
+
49
+ export default BeatifulQuestionAnimationIn;
src/player/animated/text-animated-types/animations-in/count-down-in.tsx ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ITextDetails } from "@designcombo/types";
2
+ import { interpolate } from "remotion";
3
+
4
+ const numbers = ["3", "2", "1"];
5
+
6
+ const CountDownIn = ({
7
+ text,
8
+ frame,
9
+ animationTextInFrames,
10
+ details
11
+ }: {
12
+ text: string;
13
+ frame: number;
14
+ animationTextInFrames: number;
15
+ details: ITextDetails;
16
+ }) => {
17
+ const countdownFrames = (animationTextInFrames * 3) / 4;
18
+ const framesPerNumber = Math.floor(countdownFrames / numbers.length);
19
+
20
+ let displayText = "";
21
+ let localFrame = 0;
22
+ let duration = framesPerNumber;
23
+ let initialScale = 2;
24
+ let finalScale = 0.5;
25
+ let fontSize = parseFloat(details.fontSize.toString());
26
+
27
+ if (frame < countdownFrames) {
28
+ // Mostrar el número correspondiente
29
+ const idx = Math.floor(frame / framesPerNumber);
30
+ displayText = numbers[idx];
31
+ localFrame = frame - idx * framesPerNumber;
32
+ duration = framesPerNumber;
33
+ initialScale = 2;
34
+ finalScale = 0.5;
35
+ fontSize = parseFloat(details.fontSize.toString());
36
+ } else if (frame < animationTextInFrames) {
37
+ // Mostrar el texto final con animación
38
+ displayText = text;
39
+ localFrame = frame - countdownFrames;
40
+ duration = animationTextInFrames - countdownFrames;
41
+ initialScale = 2;
42
+ finalScale = 1;
43
+ fontSize = parseFloat(details.fontSize.toString());
44
+ } else {
45
+ // Después de la animación, mostrar el texto final estático
46
+ displayText = text;
47
+ localFrame = duration;
48
+ initialScale = 1;
49
+ finalScale = 1;
50
+ fontSize = parseFloat(details.fontSize.toString());
51
+ }
52
+
53
+ const progress = Math.min(localFrame / duration, 1);
54
+ const scale = interpolate(progress, [0, 1], [initialScale, finalScale]);
55
+ const opacity = interpolate(progress, [0, 1], [0.3, 1]);
56
+ const blur = interpolate(progress, [0, 1], [8, 0]);
57
+
58
+ return (
59
+ <span
60
+ style={{
61
+ opacity,
62
+ display: "flex",
63
+ width: details.width,
64
+ height: details.height,
65
+ textAlign: "center",
66
+ justifyContent: "center",
67
+ alignItems: "center",
68
+ transform: `scale(${scale})`,
69
+ filter: `blur(${blur}px)`,
70
+ fontSize: `${fontSize}px`
71
+ }}
72
+ >
73
+ {displayText}
74
+ </span>
75
+ );
76
+ };
77
+
78
+ export default CountDownIn;
src/player/animated/text-animated-types/animations-in/descompress-in.tsx ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const DescompressAnimationIn = ({
2
+ char,
3
+ index,
4
+ frame,
5
+ fps,
6
+ animationTextInFrames
7
+ }: {
8
+ char: string;
9
+ index: number;
10
+ frame: number;
11
+ fps: number;
12
+ animationTextInFrames: number;
13
+ }) => {
14
+ const endTime = animationTextInFrames / fps;
15
+ const time = frame / fps;
16
+
17
+ const progress = Math.min(Math.max(time / endTime, 0), 1);
18
+
19
+ const scaleX = 3 - progress * 2;
20
+ const opacity = progress;
21
+
22
+ return (
23
+ <span
24
+ key={index}
25
+ style={{
26
+ display: "inline-block",
27
+ transform: `scaleX(${scaleX})`,
28
+ opacity: opacity
29
+ }}
30
+ >
31
+ {char === " " ? " " : char}
32
+ </span>
33
+ );
34
+ };
35
+
36
+ export default DescompressAnimationIn;
src/player/animated/text-animated-types/animations-in/domino-dreams-in.tsx ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { spring } from "remotion";
2
+
3
+ const DominoDreamsIn = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextInFrames
10
+ }: {
11
+ char: string;
12
+ index: number;
13
+ frame: number;
14
+ fps: number;
15
+ textLength: number;
16
+ animationTextInFrames: number;
17
+ }) => {
18
+ const totalDuration = animationTextInFrames;
19
+ const delayFactor = totalDuration / textLength;
20
+ const delay = index * delayFactor;
21
+
22
+ const rotateY = spring({
23
+ frame: frame - delay,
24
+ fps,
25
+ from: -90,
26
+ to: 0,
27
+ config: { mass: 1, damping: 12 }
28
+ });
29
+
30
+ return (
31
+ <span
32
+ key={index}
33
+ style={{
34
+ display: "inline-block",
35
+ transform: `rotateY(${rotateY}deg)`
36
+ }}
37
+ >
38
+ {char === " " ? " " : char}
39
+ </span>
40
+ );
41
+ };
42
+
43
+ export default DominoDreamsIn;
src/player/animated/text-animated-types/animations-in/drop-in.tsx ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const DropAnimationIn = ({
2
+ char,
3
+ index,
4
+ frame,
5
+ fps,
6
+ animationTextInFrames
7
+ }: {
8
+ char: string;
9
+ index: number;
10
+ frame: number;
11
+ fps: number;
12
+ animationTextInFrames: number;
13
+ }) => {
14
+ const endTime = animationTextInFrames / fps;
15
+ const time = frame / fps;
16
+
17
+ const progress = Math.min(Math.max(time / endTime, 0), 1);
18
+
19
+ const scale = 3 - progress * 2;
20
+ const opacity = progress;
21
+
22
+ return (
23
+ <span
24
+ key={index}
25
+ style={{
26
+ display: "inline-block",
27
+ transform: `scale(${scale})`,
28
+ opacity: opacity
29
+ }}
30
+ >
31
+ {char === " " ? " " : char}
32
+ </span>
33
+ );
34
+ };
35
+
36
+ export default DropAnimationIn;
src/player/animated/text-animated-types/animations-in/great-thinkers-in.tsx ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { spring } from "remotion";
2
+
3
+ const GetThinkersAnimationIn = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextInFrames
10
+ }: {
11
+ char: string;
12
+ index: number;
13
+ frame: number;
14
+ fps: number;
15
+ textLength: number;
16
+ animationTextInFrames: number;
17
+ }) => {
18
+ const totalDuration = animationTextInFrames;
19
+ const delayFactor = totalDuration / textLength;
20
+ const delay = index * delayFactor;
21
+
22
+ const opacity = spring({
23
+ frame: frame - delay,
24
+ fps,
25
+ from: 0,
26
+ to: 1,
27
+ config: { stiffness: 60, damping: 10 }
28
+ });
29
+
30
+ return (
31
+ <span
32
+ key={index}
33
+ style={{
34
+ display: "inline-block",
35
+ opacity
36
+ }}
37
+ >
38
+ {char === " " ? " " : char}
39
+ </span>
40
+ );
41
+ };
42
+
43
+ export default GetThinkersAnimationIn;
src/player/animated/text-animated-types/animations-in/made-with-love-in.tsx ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { interpolate, spring } from "remotion";
2
+
3
+ const MadeWithLoveAnimationIn = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextInFrames
10
+ }: {
11
+ char: string;
12
+ index: number;
13
+ frame: number;
14
+ fps: number;
15
+ textLength: number;
16
+ animationTextInFrames: number;
17
+ }) => {
18
+ const totalDuration = animationTextInFrames;
19
+ const delayFactor = totalDuration / textLength;
20
+ const delay = index * delayFactor; // Calculate delay for each letter
21
+
22
+ const translateY = spring({
23
+ frame: frame - delay,
24
+ fps,
25
+ from: -100,
26
+ to: 0,
27
+ config: { damping: 20, stiffness: 120 }
28
+ });
29
+
30
+ const opacity = interpolate(
31
+ frame - delay,
32
+ [0, totalDuration / 2], // Complete opacity ramp-up within half the duration
33
+ [0, 1],
34
+ {
35
+ extrapolateRight: "clamp",
36
+ extrapolateLeft: "clamp"
37
+ }
38
+ );
39
+
40
+ return (
41
+ <span
42
+ key={index}
43
+ style={{
44
+ display: "inline-block",
45
+ transform: `translateY(${translateY}px)`,
46
+ opacity
47
+ }}
48
+ >
49
+ {char === " " ? " " : char}
50
+ </span>
51
+ );
52
+ };
53
+
54
+ export default MadeWithLoveAnimationIn;
src/player/animated/text-animated-types/animations-in/reality-is-broken-in.tsx ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { interpolate, spring } from "remotion";
2
+
3
+ const RealityIsBrokenAnimationIn = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextInFrames
10
+ }: {
11
+ char: string;
12
+ index: number;
13
+ frame: number;
14
+ fps: number;
15
+ textLength: number;
16
+ animationTextInFrames: number;
17
+ }) => {
18
+ const totalDuration = animationTextInFrames;
19
+ const delayFactor = totalDuration / textLength;
20
+ const delay = index * delayFactor;
21
+
22
+ const translateY = spring({
23
+ frame: frame - delay,
24
+ fps,
25
+ from: 1.1,
26
+ to: 0,
27
+ config: { damping: 10 }
28
+ });
29
+
30
+ const translateX = spring({
31
+ frame: frame - delay,
32
+ fps,
33
+ from: 0.55,
34
+ to: 0,
35
+ config: { damping: 10 }
36
+ });
37
+
38
+ const rotateZ = spring({
39
+ frame: frame - delay,
40
+ fps,
41
+ from: 180,
42
+ to: 0,
43
+ config: { damping: 10 }
44
+ });
45
+
46
+ const opacity = interpolate(
47
+ frame,
48
+ [delay, delay + 15], // Adjust for opacity ramp-up
49
+ [0, 1],
50
+ {
51
+ extrapolateRight: "clamp",
52
+ extrapolateLeft: "clamp"
53
+ }
54
+ );
55
+
56
+ return (
57
+ <span
58
+ key={index}
59
+ style={{
60
+ display: "inline-block",
61
+ transformOrigin: "0 100%",
62
+ transform: `translateY(${translateY}em) translateX(${translateX}em) rotateZ(${rotateZ}deg)`,
63
+ opacity
64
+ }}
65
+ >
66
+ {char === " " ? " " : char}
67
+ </span>
68
+ );
69
+ };
70
+
71
+ export default RealityIsBrokenAnimationIn;
src/player/animated/text-animated-types/animations-in/rising-strong-in.tsx ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { interpolate } from "remotion";
2
+
3
+ const RisingStrongAnimationIn = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ textLength,
8
+ animationTextInFrames
9
+ }: {
10
+ char: string;
11
+ index: number;
12
+ frame: number;
13
+ textLength: number;
14
+ animationTextInFrames: number;
15
+ }) => {
16
+ const totalDuration = animationTextInFrames / 2;
17
+ const delayFactor = totalDuration / textLength;
18
+ const appearDelay = index * delayFactor;
19
+
20
+ // Adjust the disappearance to happen after the complete animation if needed
21
+ const disappearStart = totalDuration + appearDelay;
22
+
23
+ const opacity = interpolate(
24
+ frame - appearDelay,
25
+ [0, totalDuration / 2, disappearStart, disappearStart + totalDuration / 2],
26
+ [0, 1, 1, 0],
27
+ { extrapolateLeft: "clamp", extrapolateRight: "clamp" }
28
+ );
29
+
30
+ const translateY = interpolate(
31
+ frame - appearDelay,
32
+ [0, totalDuration],
33
+ [100, 0],
34
+ { extrapolateLeft: "clamp", extrapolateRight: "clamp" }
35
+ );
36
+
37
+ return (
38
+ <span
39
+ key={index}
40
+ style={{
41
+ display: "inline-block",
42
+ transform: `translateY(${translateY}px)`,
43
+ opacity
44
+ }}
45
+ >
46
+ {char === " " ? " " : char}
47
+ </span>
48
+ );
49
+ };
50
+
51
+ export default RisingStrongAnimationIn;
src/player/animated/text-animated-types/animations-in/sound-wave-in.tsx ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ITextDetails } from "@designcombo/types";
2
+ import { interpolate } from "remotion";
3
+
4
+ const SoundWaveIn = ({
5
+ text,
6
+ frame,
7
+ animationTextInFrames,
8
+ details
9
+ }: {
10
+ text: string;
11
+ frame: number;
12
+ animationTextInFrames: number;
13
+ details: ITextDetails;
14
+ }) => {
15
+ const waveDisappearStart = animationTextInFrames * 0.5;
16
+ const waveDisappearEnd = animationTextInFrames;
17
+ const trailCount = 8;
18
+ const baseScale = interpolate(frame, [0, waveDisappearStart], [0.5, 1], {
19
+ extrapolateRight: "clamp"
20
+ });
21
+ const mainScale = baseScale;
22
+ const mainBlur = 0;
23
+ const mainOpacity = 1;
24
+ const waveScaleX = interpolate(frame, [0, waveDisappearStart], [2, 1], {
25
+ extrapolateRight: "clamp"
26
+ });
27
+ const waveBlur =
28
+ frame < waveDisappearStart
29
+ ? interpolate(frame, [0, waveDisappearStart], [20, 0], {
30
+ extrapolateRight: "clamp"
31
+ })
32
+ : interpolate(frame, [waveDisappearStart, waveDisappearEnd], [0, 40], {
33
+ extrapolateLeft: "clamp",
34
+ extrapolateRight: "clamp"
35
+ });
36
+ // Opacidad: de 0.7 a 1, luego a 0
37
+ const waveOpacity =
38
+ frame < waveDisappearStart
39
+ ? interpolate(frame, [0, waveDisappearStart], [0.7, 1], {
40
+ extrapolateRight: "clamp"
41
+ })
42
+ : interpolate(frame, [waveDisappearStart, waveDisappearEnd], [1, 0], {
43
+ extrapolateLeft: "clamp",
44
+ extrapolateRight: "clamp"
45
+ });
46
+
47
+ const trails = [];
48
+ for (let i = trailCount; i > 0; i--) {
49
+ // Cada trail está más atrás en el tiempo
50
+ const trailFrame = Math.max(frame - i * 2, 0);
51
+
52
+ // Escalado y estiramiento X para el efecto de eco
53
+ const trailScale = interpolate(
54
+ trailFrame,
55
+ [0, waveDisappearStart],
56
+ [0.5, 1],
57
+ { extrapolateRight: "clamp" }
58
+ );
59
+ // const trailScaleX = interpolate(
60
+ // trailFrame,
61
+ // [0, waveDisappearStart],
62
+ // [2.5, 1],
63
+ // { extrapolateRight: "clamp" },
64
+ // );
65
+
66
+ // Opacidad más baja para los trails lejanos
67
+ const trailOpacity = interpolate(
68
+ trailFrame,
69
+ [0, waveDisappearStart],
70
+ [0.15, 0],
71
+ { extrapolateRight: "clamp" }
72
+ );
73
+
74
+ trails.push(
75
+ <span
76
+ key={i}
77
+ style={{
78
+ position: "absolute",
79
+ top: 0,
80
+ left: 0,
81
+ opacity: trailOpacity,
82
+ transform: `scale(${trailScale * 2})`,
83
+ pointerEvents: "none"
84
+ }}
85
+ >
86
+ {text}
87
+ </span>
88
+ );
89
+ }
90
+ return (
91
+ <div
92
+ style={{
93
+ display: "flex",
94
+ width: details.width,
95
+ height: details.height,
96
+ transform: `scale(${baseScale})`,
97
+ position: "relative"
98
+ }}
99
+ >
100
+ {/* Texto wave */}
101
+
102
+ <span
103
+ style={{
104
+ width: details.width,
105
+ height: details.height,
106
+ background: "transparent",
107
+ transform: `scale(${mainScale})`
108
+ }}
109
+ >
110
+ {text}
111
+ </span>
112
+ <span
113
+ style={{
114
+ position: "absolute",
115
+ opacity: waveOpacity,
116
+ width: details.width,
117
+ height: details.height,
118
+ transform: `scaleX(${waveScaleX})`,
119
+ filter: `blur(${waveBlur * 3}px)`
120
+ }}
121
+ >
122
+ {text}
123
+ </span>
124
+ {/* </span> */}
125
+ <span
126
+ style={{
127
+ opacity: mainOpacity,
128
+ filter: `blur(${mainBlur}px)`,
129
+ transform: `scale(${mainScale})`,
130
+ fontSize: parseFloat(details.fontSize.toString()),
131
+ position: "absolute",
132
+ width: details.width,
133
+ height: details.height
134
+ }}
135
+ >
136
+ <div
137
+ style={{
138
+ width: details.width,
139
+ height: details.height,
140
+ position: "relative"
141
+ }}
142
+ >
143
+ {trails}
144
+ </div>
145
+ </span>
146
+ </div>
147
+ );
148
+ };
149
+
150
+ export default SoundWaveIn;
src/player/animated/text-animated-types/animations-in/sunny-mornings-in.tsx ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { interpolate, spring } from "remotion";
2
+
3
+ const SunnyMorningsAnimationIn = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextInFrames
10
+ }: {
11
+ char: string;
12
+ index: number;
13
+ frame: number;
14
+ fps: number;
15
+ textLength: number;
16
+ animationTextInFrames: number;
17
+ }) => {
18
+ const totalDuration = animationTextInFrames;
19
+ const delayFactor = totalDuration / (textLength + 1);
20
+ const delay = index * delayFactor;
21
+
22
+ const scale = spring({
23
+ frame: frame - delay,
24
+ fps,
25
+ from: 4,
26
+ to: 1,
27
+ config: { mass: 1, damping: 10 }
28
+ });
29
+
30
+ const opacity = interpolate(
31
+ frame - delay,
32
+ [0, totalDuration / 2], // Ensure opacity fades in within half the duration
33
+ [0, 1],
34
+ { extrapolateLeft: "clamp", extrapolateRight: "clamp" }
35
+ );
36
+
37
+ return (
38
+ <span
39
+ key={index}
40
+ style={{
41
+ display: "inline-block",
42
+ transform: `scale(${scale})`,
43
+ opacity: opacity
44
+ }}
45
+ >
46
+ {char === " " ? " " : char}
47
+ </span>
48
+ );
49
+ };
50
+
51
+ export default SunnyMorningsAnimationIn;
src/player/animated/text-animated-types/animations-in/text-animated-in.tsx ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { spring } from "remotion";
2
+
3
+ const AnimatedTextIn = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextInFrames
10
+ }: {
11
+ char: string;
12
+ index: number;
13
+ frame: number;
14
+ fps: number;
15
+ textLength: number;
16
+ animationTextInFrames: number;
17
+ }) => {
18
+ // Adjust delay based on total frames available for the entire animation
19
+ const totalDelay = animationTextInFrames;
20
+ const delayFactor = totalDelay / textLength;
21
+ const delay = index * delayFactor;
22
+
23
+ const opacity = spring({
24
+ frame: frame - delay,
25
+ fps,
26
+ from: 0,
27
+ to: 1,
28
+ config: { mass: 0.5, damping: 10 }
29
+ });
30
+
31
+ const y = spring({
32
+ frame: frame - delay,
33
+ fps,
34
+ from: -50,
35
+ to: 0,
36
+ config: { mass: 0.5, damping: 10 }
37
+ });
38
+
39
+ const rotate = spring({
40
+ frame: frame - delay,
41
+ fps,
42
+ from: -180,
43
+ to: 0,
44
+ config: { mass: 0.5, damping: 12 }
45
+ });
46
+
47
+ return (
48
+ <span
49
+ key={index}
50
+ style={{
51
+ display: "inline-block",
52
+ opacity,
53
+ transform: `translateY(${y}px) rotate(${rotate}deg)`,
54
+ transition: "all 0.05s ease-out"
55
+ }}
56
+ >
57
+ {char === " " ? " " : char}
58
+ </span>
59
+ );
60
+ };
61
+
62
+ export default AnimatedTextIn;
src/player/animated/text-animated-types/animations-in/type-writer-in.tsx ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ITextDetails } from "@designcombo/types";
2
+ import { useMemo } from "react";
3
+ import { interpolate } from "remotion";
4
+
5
+ export default function TypeWriterIn({
6
+ frame,
7
+ durationInFrames,
8
+ text,
9
+ style
10
+ }: {
11
+ frame: number;
12
+ durationInFrames: number;
13
+ text: string;
14
+ style: ITextDetails;
15
+ }) {
16
+ const visibleCharacters = Math.floor(
17
+ interpolate(frame, [0, durationInFrames], [0, text.length], {
18
+ extrapolateRight: "clamp"
19
+ })
20
+ );
21
+
22
+ const visibleText = useMemo(() => {
23
+ let count = 0;
24
+ return text
25
+ .split(" ")
26
+ .map((word) => {
27
+ if (count + word.length <= visibleCharacters) {
28
+ count += word.length + 1;
29
+ return word;
30
+ }
31
+ if (count < visibleCharacters) {
32
+ const partialWord = word.slice(0, visibleCharacters - count);
33
+ count = visibleCharacters;
34
+ return partialWord;
35
+ }
36
+ return "";
37
+ })
38
+ .join(" ");
39
+ }, [visibleCharacters]);
40
+
41
+ return (
42
+ <div
43
+ style={{
44
+ textAlign: "center"
45
+ }}
46
+ >
47
+ <span
48
+ style={{
49
+ fontSize: style.fontSize
50
+ }}
51
+ >
52
+ {visibleText}
53
+ </span>
54
+ <span
55
+ style={{
56
+ color: "#60a5fa",
57
+ opacity: frame % 15 < 7 ? 1 : 0
58
+ }}
59
+ >
60
+ |
61
+ </span>
62
+ </div>
63
+ );
64
+ }
src/player/animated/text-animated-types/animations-loop/billboard.tsx ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const BillboardText = ({
2
+ frame,
3
+ fps,
4
+ char
5
+ }: {
6
+ char: string;
7
+ frame: number;
8
+ fps: number;
9
+ }) => {
10
+ const scale = 1 + 0.2 * Math.sin((2 * Math.PI * frame) / (fps * 1)); // 1 ciclo por segundo
11
+
12
+ return (
13
+ <span
14
+ style={{
15
+ display: "inline-block",
16
+ transform: `scale(${scale})`
17
+ }}
18
+ >
19
+ {char}
20
+ </span>
21
+ );
22
+ };
23
+
24
+ export default BillboardText;
src/player/animated/text-animated-types/animations-loop/dragonfly.tsx ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const DragonflyText = ({
2
+ char,
3
+ frame,
4
+ fps
5
+ }: {
6
+ char: string;
7
+ frame: number;
8
+ fps: number;
9
+ }) => {
10
+ const t = frame / fps;
11
+
12
+ const x = 80 * Math.sin(t * 2 * Math.PI); // movimiento lateral
13
+ const y = 80 * Math.sin(t * 2.5 * Math.PI); // movimiento vertical
14
+ const rotate = 5 * Math.sin(t * 3 * Math.PI); // rotación en grados
15
+ const scale = 1 + 0.05 * Math.sin(t * 4 * Math.PI); // pequeño pulso
16
+
17
+ return (
18
+ <span
19
+ style={{
20
+ display: "inline-block",
21
+ transform: `translate(${x}px, ${y}px) rotate(${rotate}deg) scale(${scale})`,
22
+ transition: "transform 0.1s linear"
23
+ }}
24
+ >
25
+ {char}
26
+ </span>
27
+ );
28
+ };
29
+
30
+ export default DragonflyText;
src/player/animated/text-animated-types/animations-loop/font-change.tsx ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ITextDetails } from "@designcombo/types";
2
+
3
+ const FontChange = ({
4
+ frame,
5
+ text,
6
+ details,
7
+ animationFonts
8
+ }: {
9
+ text: string;
10
+ frame: number;
11
+ details: ITextDetails;
12
+ animationFonts: { fontFamily: string; url: string }[];
13
+ }) => {
14
+ const totalFonts = [{ fontFamily: details.fontFamily }, ...animationFonts];
15
+ const cycleDuration = 30; // Duración de un ciclo completo en frames
16
+ const framesPerFont = cycleDuration / totalFonts.length; // Frames por cada fuente
17
+
18
+ const fontIndex = Math.floor((frame % cycleDuration) / framesPerFont);
19
+
20
+ return (
21
+ <div
22
+ style={{
23
+ width: "100%",
24
+ height: "100%",
25
+ position: "relative",
26
+ background: "transparent",
27
+ perspective: 1000 // necesaria para el efecto 3D
28
+ }}
29
+ >
30
+ <div
31
+ style={{
32
+ fontFamily: totalFonts[fontIndex].fontFamily
33
+ }}
34
+ >
35
+ {text}
36
+ </div>
37
+ </div>
38
+ );
39
+ };
40
+
41
+ export default FontChange;
src/player/animated/text-animated-types/animations-loop/glitch.tsx ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const GlitchText = ({ text, frame }: { text: string; frame: number }) => {
2
+ const glitchIntensity = Math.sin(frame / 10) * 10;
3
+ const rgbOffset = Math.sin(frame / 5) * 10;
4
+
5
+ return (
6
+ <span
7
+ style={{
8
+ display: "inline-block",
9
+ position: "relative",
10
+ opacity: 0.8
11
+ }}
12
+ >
13
+ <div
14
+ style={{
15
+ position: "absolute",
16
+ color: "cyan",
17
+ transform: `translate(${rgbOffset}px, ${glitchIntensity}px)`,
18
+ mixBlendMode: "screen"
19
+ }}
20
+ >
21
+ {text}
22
+ </div>
23
+ <div
24
+ style={{
25
+ position: "absolute",
26
+ color: "magenta",
27
+ transform: `translate(${-rgbOffset}px, ${-glitchIntensity}px)`,
28
+ mixBlendMode: "screen"
29
+ }}
30
+ >
31
+ {text}
32
+ </div>
33
+ <div style={{ color: "white" }}>
34
+ <span style={{ paddingInline: "10px" }}>{text}</span>
35
+ </div>
36
+ </span>
37
+ );
38
+ };
39
+
40
+ export default GlitchText;
src/player/animated/text-animated-types/animations-loop/heartbeat.tsx ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const Heartbeat = ({
2
+ char,
3
+ frame,
4
+ fps
5
+ }: {
6
+ char: string;
7
+ frame: number;
8
+ fps: number;
9
+ }) => {
10
+ const time = frame / fps;
11
+ const cycleDuration = 1;
12
+ const cycleTime = time % cycleDuration;
13
+
14
+ let scale = 1;
15
+ if (cycleTime < 0.2 || (cycleTime >= 0.3 && cycleTime < 0.5)) {
16
+ scale = 1 + Math.sin((cycleTime % 0.2) * Math.PI * 5) * 0.8;
17
+ }
18
+
19
+ return (
20
+ <span
21
+ style={{
22
+ display: "inline-block",
23
+ transform: `scale(${scale})`
24
+ }}
25
+ >
26
+ {char}
27
+ </span>
28
+ );
29
+ };
30
+ export default Heartbeat;
src/player/animated/text-animated-types/animations-loop/pulse.tsx ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ITextDetails } from "@designcombo/types";
2
+ import { interpolate } from "remotion";
3
+
4
+ const PulseText = ({
5
+ char,
6
+ index,
7
+ frame,
8
+ details
9
+ }: {
10
+ char: string;
11
+ index: number;
12
+ frame: number;
13
+ details: ITextDetails;
14
+ }) => {
15
+ const delay = index * 6;
16
+ const pulse = interpolate(
17
+ ((frame + 30 - delay) % 30) / 30,
18
+ [0, 0.5, 1],
19
+ [1, 1.2, 1],
20
+ {
21
+ extrapolateRight: "clamp"
22
+ }
23
+ );
24
+ const opacity = interpolate(
25
+ ((frame + 30 - delay) % 30) / 30,
26
+ [0, 0.5, 1],
27
+ [0.5, 1, 0.5],
28
+ {
29
+ extrapolateRight: "clamp"
30
+ }
31
+ );
32
+
33
+ return (
34
+ <span
35
+ style={{
36
+ opacity: opacity,
37
+ position: "relative",
38
+ fontSize: parseFloat(details.fontSize.toString()) * pulse,
39
+ scale: pulse
40
+ }}
41
+ >
42
+ {char}
43
+ <div
44
+ style={{
45
+ position: "absolute",
46
+ top: "50%",
47
+ left: "50%",
48
+ transform: "translate(-50%, -50%)",
49
+ width: parseFloat(details.fontSize.toString()) * 1.5,
50
+ height: parseFloat(details.fontSize.toString()) * 1.5,
51
+ background: "rgba(255, 255, 255, 0.1)",
52
+ borderRadius: "50%",
53
+ filter: "blur(20px)",
54
+ opacity: opacity
55
+ }}
56
+ />
57
+ </span>
58
+ );
59
+ };
60
+
61
+ export default PulseText;
src/player/animated/text-animated-types/animations-loop/rotate-3d.tsx ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { interpolate } from "remotion";
2
+
3
+ const Rotate3d = ({
4
+ frame,
5
+ durationInFrames,
6
+ text
7
+ }: {
8
+ text: string;
9
+ frame: number;
10
+ durationInFrames: number;
11
+ }) => {
12
+ const rotation = interpolate(frame, [0, durationInFrames / 2], [0, 360]);
13
+ const rotation2 = rotation - 90;
14
+
15
+ return (
16
+ <div
17
+ style={{
18
+ width: "100%",
19
+ height: "100%",
20
+ position: "relative",
21
+ background: "transparent",
22
+ perspective: 1000 // necesaria para el efecto 3D
23
+ }}
24
+ >
25
+ <div
26
+ style={{
27
+ transform: `rotateY(${rotation}deg)`,
28
+ transformStyle: "preserve-3d",
29
+ background: "transparent"
30
+ }}
31
+ >
32
+ {text}
33
+ </div>
34
+ <div
35
+ style={{
36
+ transform: `rotateY(${rotation2}deg)`,
37
+ transformStyle: "preserve-3d",
38
+ position: "absolute",
39
+ top: 0,
40
+ background: "transparent"
41
+ }}
42
+ >
43
+ {text}
44
+ </div>
45
+ </div>
46
+ );
47
+ };
48
+
49
+ export default Rotate3d;
src/player/animated/text-animated-types/animations-loop/shake-text.tsx ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function random(seed: number) {
2
+ const x = Math.sin(seed) * 10000;
3
+ return x - Math.floor(x);
4
+ }
5
+
6
+ const ShakeText = ({ text, frame }: { text: string; frame: number }) => {
7
+ const offsetX = (random(frame) - 0.5) * 8; // entre -4 y 4 px
8
+ const offsetY = (random(frame + 999) - 0.5) * 8;
9
+ const rotate = (random(frame + 500) - 0.5) * 6; // entre -3 y 3 grados
10
+
11
+ return (
12
+ <span
13
+ style={{
14
+ display: "inline-block",
15
+ transform: `translate(${offsetX}px, ${offsetY}px) rotate(${rotate}deg)`
16
+ }}
17
+ >
18
+ {text}
19
+ </span>
20
+ );
21
+ };
22
+
23
+ export default ShakeText;
src/player/animated/text-animated-types/animations-loop/shaky-letters-text.tsx ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function random(seed: number) {
2
+ const x = Math.sin(seed) * 10000;
3
+ return x - Math.floor(x);
4
+ }
5
+
6
+ const ShakyLettersText = ({
7
+ char,
8
+ index,
9
+ frame
10
+ }: {
11
+ char: string;
12
+ index: number;
13
+ frame: number;
14
+ }) => {
15
+ const seed = frame * 100 + index * 999;
16
+ const offsetX = (random(seed) - 0.5) * 8;
17
+ const offsetY = (random(seed + 1) - 0.5) * 8;
18
+ const rotate = (random(seed + 2) - 0.5) * 6;
19
+
20
+ return (
21
+ <span
22
+ key={index}
23
+ style={{
24
+ display: "inline-block",
25
+ transform: `translate(${offsetX}px, ${offsetY}px) rotate(${rotate}deg)`
26
+ }}
27
+ >
28
+ {char}
29
+ </span>
30
+ );
31
+ };
32
+
33
+ export default ShakyLettersText;
src/player/animated/text-animated-types/animations-loop/spin.tsx ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const Spin = ({
2
+ text,
3
+ frame,
4
+ fps
5
+ }: {
6
+ text: string;
7
+ frame: number;
8
+ fps: number;
9
+ }) => {
10
+ const t = frame / fps;
11
+ const rotateZ = t * 360;
12
+
13
+ return (
14
+ <span
15
+ style={{
16
+ display: "inline-block",
17
+ transform: `rotateZ(${rotateZ}deg)`
18
+ }}
19
+ >
20
+ {text}
21
+ </span>
22
+ );
23
+ };
24
+ export default Spin;
src/player/animated/text-animated-types/animations-loop/vintage.tsx ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { interpolate } from "remotion";
2
+
3
+ const TOTAL_LAYERS = 9;
4
+
5
+ const Vintage = ({
6
+ text,
7
+ frame,
8
+ details,
9
+ fps
10
+ }: {
11
+ text: string;
12
+ frame: number;
13
+ details: {
14
+ fontSize: number;
15
+ color: string;
16
+ };
17
+ fps: number;
18
+ }) => {
19
+ const duration = fps;
20
+ const half = duration / 2;
21
+ const layerCount = Math.round(
22
+ frame % fps <= half
23
+ ? interpolate(frame % fps, [0, half], [1, TOTAL_LAYERS])
24
+ : interpolate(frame % fps, [half, duration], [TOTAL_LAYERS, 1])
25
+ );
26
+
27
+ return (
28
+ <div
29
+ style={{
30
+ width: "100%",
31
+ height: "100%",
32
+ position: "relative"
33
+ }}
34
+ >
35
+ {Array.from({ length: layerCount }).map((_, i) => {
36
+ const dx = i * 4;
37
+ const dy = -i * 2;
38
+ const opacity = 1 / (layerCount - i);
39
+
40
+ return (
41
+ <div
42
+ key={i}
43
+ style={{
44
+ position: "absolute",
45
+ transform: `translate(${dx * 4}px, ${dy * 4}px)`,
46
+ fontWeight: "bold",
47
+ fontSize: details.fontSize,
48
+ zIndex: i,
49
+ color: layerCount !== i + 1 ? "red" : details.color,
50
+ background: "transparent",
51
+ opacity
52
+ }}
53
+ >
54
+ {text}
55
+ </div>
56
+ );
57
+ })}
58
+ </div>
59
+ );
60
+ };
61
+
62
+ export default Vintage;
src/player/animated/text-animated-types/animations-loop/vogue.tsx ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const VogueLetterByLetter = ({
2
+ char,
3
+ frame,
4
+ fps,
5
+ index
6
+ }: {
7
+ char: string;
8
+ frame: number;
9
+ fps: number;
10
+ index: number;
11
+ }) => {
12
+ const delay = index * 4; // desfase por letra
13
+ const t = (frame - delay) / fps;
14
+
15
+ // Loop suave con rotación más notoria
16
+ const scale = 1 + 0.25 * Math.sin(t * 2 * Math.PI);
17
+ const rotateY = 40 * Math.sin(t * 2 * Math.PI);
18
+
19
+ return (
20
+ <span
21
+ style={{
22
+ display: "inline-block",
23
+ transform: `scale(${scale}) rotateY(${rotateY}deg)`
24
+ }}
25
+ >
26
+ {char}
27
+ </span>
28
+ );
29
+ };
30
+ export default VogueLetterByLetter;
src/player/animated/text-animated-types/animations-loop/wave.tsx ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const Wave = ({
2
+ char,
3
+ frame,
4
+ fps,
5
+ index
6
+ }: {
7
+ char: string;
8
+ frame: number;
9
+ fps: number;
10
+ index: number;
11
+ }) => {
12
+ const offset = index * 20;
13
+ const translateY = Math.sin((frame * 8 - offset) / fps) * 20;
14
+
15
+ return (
16
+ <span
17
+ style={{
18
+ display: "inline-block",
19
+ transform: `translateY(${translateY}px)`
20
+ }}
21
+ >
22
+ {char}
23
+ </span>
24
+ );
25
+ };
26
+ export default Wave;
src/player/animated/text-animated-types/animations-out/background-out.tsx ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ITextDetails } from "@designcombo/types";
2
+ import { interpolate } from "remotion";
3
+
4
+ const BackgroundOut = ({
5
+ text,
6
+ frame,
7
+ animationTextOutFrames,
8
+ details,
9
+ durationInFrames,
10
+ fps
11
+ }: {
12
+ text: string;
13
+ frame: number;
14
+ animationTextOutFrames: number;
15
+ details: ITextDetails;
16
+ durationInFrames: number;
17
+ fps: number;
18
+ }) => {
19
+ const start = durationInFrames - animationTextOutFrames;
20
+ const duration = animationTextOutFrames;
21
+
22
+ // Progreso de la animación de salida
23
+ const progress = interpolate(frame, [start, start + duration], [0, 1], {
24
+ extrapolateRight: "clamp"
25
+ });
26
+ const fullWidth = details.width;
27
+ const fullHeight = details.height;
28
+
29
+ // El rectángulo se reduce de ancho completo a 0
30
+ const revealWidth = interpolate(
31
+ Math.round(progress * 100),
32
+ [0, 100 - fps / 10],
33
+ [fullWidth, 0]
34
+ );
35
+ // El texto se mueve del centro hacia la derecha
36
+ const textTranslateX = interpolate(progress, [0, 1], [0, fullWidth * 2]);
37
+
38
+ return (
39
+ <div
40
+ style={{
41
+ flex: 1,
42
+ position: "relative",
43
+ justifyContent: "flex-start",
44
+ alignItems: "center",
45
+ display: "flex",
46
+ width: details.width,
47
+ height: details.height
48
+ }}
49
+ >
50
+ {/* Máscara que oculta el texto fuera del rectángulo */}
51
+ <div
52
+ style={{
53
+ width: revealWidth,
54
+ height: fullHeight,
55
+ overflow: "hidden",
56
+ display: "flex",
57
+ position: "relative",
58
+ alignItems: "center",
59
+ justifyContent: "center",
60
+ backgroundColor: "white"
61
+ }}
62
+ >
63
+ <div
64
+ style={{
65
+ fontSize: parseFloat(details.fontSize.toString()),
66
+ display: "flex",
67
+ position: "absolute",
68
+ justifyContent: "center",
69
+ alignItems: "center",
70
+ width: details.width,
71
+ height: details.height,
72
+ color:
73
+ details.color === "white" || details.color.includes("fff")
74
+ ? "black"
75
+ : details.color,
76
+ transform: `translateX(${textTranslateX}px)`
77
+ }}
78
+ >
79
+ {text}
80
+ </div>
81
+ </div>
82
+ </div>
83
+ );
84
+ };
85
+
86
+ export default BackgroundOut;
src/player/animated/text-animated-types/animations-out/beatiful-question-out.tsx ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { interpolate, spring } from "remotion";
2
+
3
+ const BeatifulQuestionAnimationOut = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextOutFrames,
10
+ durationInFrames
11
+ }: {
12
+ char: string;
13
+ index: number;
14
+ frame: number;
15
+ fps: number;
16
+ textLength: number;
17
+ animationTextOutFrames: number;
18
+ durationInFrames: number;
19
+ }) => {
20
+ const exitDuration = animationTextOutFrames;
21
+ const delayPerChar = exitDuration / textLength;
22
+ const exitStart = durationInFrames - animationTextOutFrames;
23
+ const charExitStart = exitStart + index * delayPerChar;
24
+ const progress = frame - charExitStart;
25
+
26
+ const translateY = spring({
27
+ frame: progress,
28
+ fps,
29
+ from: 0,
30
+ to: 1.1,
31
+ config: { damping: 10 }
32
+ });
33
+
34
+ const opacity = interpolate(progress, [0, delayPerChar], [1, 0], {
35
+ extrapolateRight: "clamp",
36
+ extrapolateLeft: "clamp"
37
+ });
38
+ return (
39
+ <span
40
+ key={index}
41
+ style={{
42
+ display: "inline-block",
43
+ transform: `translateY(${translateY}em)`,
44
+ opacity
45
+ }}
46
+ >
47
+ {char === " " ? " " : char}
48
+ </span>
49
+ );
50
+ };
51
+
52
+ export default BeatifulQuestionAnimationOut;
src/player/animated/text-animated-types/animations-out/descompress-out.tsx ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const DescompressAnimationOut = ({
2
+ char,
3
+ index,
4
+ frame,
5
+ fps,
6
+ animationTextOutFrames,
7
+ durationInFrames
8
+ }: {
9
+ char: string;
10
+ index: number;
11
+ frame: number;
12
+ fps: number;
13
+ animationTextOutFrames: number;
14
+ durationInFrames: number;
15
+ }) => {
16
+ const startTime = (durationInFrames - animationTextOutFrames) / fps;
17
+ const endTime = durationInFrames / fps;
18
+ const time = frame / fps;
19
+
20
+ const progress = Math.min(
21
+ Math.max((time - startTime) / (endTime - startTime), 0),
22
+ 1
23
+ );
24
+ const scaleX = 1 + progress;
25
+ const opacity = 1 - progress;
26
+
27
+ return (
28
+ <span
29
+ key={index}
30
+ style={{
31
+ display: "inline-block",
32
+ transform: `scaleX(${scaleX})`,
33
+ opacity: opacity
34
+ }}
35
+ >
36
+ {char === " " ? " " : char}
37
+ </span>
38
+ );
39
+ };
40
+
41
+ export default DescompressAnimationOut;
src/player/animated/text-animated-types/animations-out/domino-dreams-out.tsx ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { spring } from "remotion";
2
+
3
+ const DominoDreamsAnimationOut = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextOutFrames,
10
+ durationInFrames
11
+ }: {
12
+ char: string;
13
+ index: number;
14
+ frame: number;
15
+ fps: number;
16
+ textLength: number;
17
+ animationTextOutFrames: number;
18
+ durationInFrames: number;
19
+ }) => {
20
+ const exitDuration = animationTextOutFrames;
21
+ const delayPerChar = exitDuration / textLength;
22
+ const exitStart = durationInFrames - animationTextOutFrames;
23
+ const charExitStart = exitStart + index * delayPerChar;
24
+ const progress = frame - charExitStart;
25
+
26
+ const rotateY = spring({
27
+ frame: progress,
28
+ fps,
29
+ from: 0,
30
+ to: 90,
31
+ config: { mass: 1, damping: 12 }
32
+ });
33
+
34
+ return (
35
+ <span
36
+ key={index}
37
+ style={{
38
+ display: "inline-block",
39
+ transform: `rotateY(${rotateY}deg)`
40
+ }}
41
+ >
42
+ {char === " " ? " " : char}
43
+ </span>
44
+ );
45
+ };
46
+
47
+ export default DominoDreamsAnimationOut;
src/player/animated/text-animated-types/animations-out/drop-out.tsx ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const DropAnimationOut = ({
2
+ char,
3
+ index,
4
+ frame,
5
+ fps,
6
+ animationTextOutFrames,
7
+ durationInFrames
8
+ }: {
9
+ char: string;
10
+ index: number;
11
+ frame: number;
12
+ fps: number;
13
+ animationTextOutFrames: number;
14
+ durationInFrames: number;
15
+ }) => {
16
+ const startTime = (durationInFrames - animationTextOutFrames) / fps;
17
+ const endTime = durationInFrames / fps;
18
+ const time = frame / fps;
19
+
20
+ const progress = Math.min(
21
+ Math.max((time - startTime) / (endTime - startTime), 0),
22
+ 1
23
+ );
24
+
25
+ const scale = 1 + progress;
26
+ const opacity = 1 - progress;
27
+
28
+ return (
29
+ <span
30
+ key={index}
31
+ style={{
32
+ display: "inline-block",
33
+ transform: `scale(${scale})`,
34
+ opacity: opacity
35
+ }}
36
+ >
37
+ {char === " " ? " " : char}
38
+ </span>
39
+ );
40
+ };
41
+
42
+ export default DropAnimationOut;
src/player/animated/text-animated-types/animations-out/great-thinkers-out.tsx ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { spring } from "remotion";
2
+
3
+ const GreatThinkersAnimationOut = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextOutFrames,
10
+ durationInFrames
11
+ }: {
12
+ char: string;
13
+ index: number;
14
+ frame: number;
15
+ fps: number;
16
+ textLength: number;
17
+ animationTextOutFrames: number;
18
+ durationInFrames: number;
19
+ }) => {
20
+ const exitStart = durationInFrames - animationTextOutFrames;
21
+ const delayPerChar = animationTextOutFrames / textLength;
22
+ const charExitStart = exitStart + index * delayPerChar;
23
+ const progress = frame - charExitStart;
24
+
25
+ const opacity = spring({
26
+ frame: progress,
27
+ fps,
28
+ from: 1,
29
+ to: 0,
30
+ config: { stiffness: 60, damping: 10 }
31
+ });
32
+
33
+ return (
34
+ <span
35
+ key={index}
36
+ style={{
37
+ display: "inline-block",
38
+ opacity
39
+ }}
40
+ >
41
+ {char === " " ? " " : char}
42
+ </span>
43
+ );
44
+ };
45
+
46
+ export default GreatThinkersAnimationOut;
src/player/animated/text-animated-types/animations-out/made-with-love-out.tsx ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { interpolate, spring } from "remotion";
2
+
3
+ const MadeWithLoveAnimationOut = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextOutFrames,
10
+ durationInFrames
11
+ }: {
12
+ char: string;
13
+ index: number;
14
+ frame: number;
15
+ fps: number;
16
+ textLength: number;
17
+ animationTextOutFrames: number;
18
+ durationInFrames: number;
19
+ }) => {
20
+ const exitStart = durationInFrames - animationTextOutFrames;
21
+ const delayPerChar = animationTextOutFrames / textLength;
22
+ const charExitStart = exitStart + index * delayPerChar;
23
+ const progress = frame - charExitStart;
24
+
25
+ const translateY = spring({
26
+ frame: progress,
27
+ fps,
28
+ from: 0,
29
+ to: 100, // Move text out of view
30
+ config: { damping: 20, stiffness: 120 }
31
+ });
32
+
33
+ const opacity = interpolate(
34
+ progress,
35
+ [0, delayPerChar], // Frames for opacity fade-out
36
+ [1, 0],
37
+ {
38
+ extrapolateRight: "clamp",
39
+ extrapolateLeft: "clamp"
40
+ }
41
+ );
42
+
43
+ return (
44
+ <span
45
+ key={index}
46
+ style={{
47
+ display: "inline-block",
48
+ transform: `translateY(${translateY}px)`,
49
+ opacity
50
+ }}
51
+ >
52
+ {char === " " ? "\u00A0" : char}
53
+ </span>
54
+ );
55
+ };
56
+
57
+ export default MadeWithLoveAnimationOut;
src/player/animated/text-animated-types/animations-out/reality-is-broken-out.tsx ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { interpolate, spring } from "remotion";
2
+
3
+ const RealityIsBrokenAnimationOut = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextOutFrames,
10
+ durationInFrames
11
+ }: {
12
+ char: string;
13
+ index: number;
14
+ frame: number;
15
+ fps: number;
16
+ textLength: number;
17
+ animationTextOutFrames: number;
18
+ durationInFrames: number;
19
+ }) => {
20
+ const exitStart = durationInFrames - animationTextOutFrames;
21
+ const delayPerChar = animationTextOutFrames / textLength;
22
+ const charExitStart = exitStart + index * delayPerChar;
23
+ const progress = frame - charExitStart;
24
+
25
+ const translateY = spring({
26
+ frame: progress,
27
+ fps,
28
+ from: 0,
29
+ to: 1,
30
+ config: { mass: 1, damping: 10 }
31
+ });
32
+
33
+ const translateX = spring({
34
+ frame: progress,
35
+ fps,
36
+ from: 0,
37
+ to: 0.55,
38
+ config: { mass: 1, damping: 10 }
39
+ });
40
+
41
+ const rotateZ = spring({
42
+ frame: progress,
43
+ fps,
44
+ from: 0,
45
+ to: 180,
46
+ config: { mass: 1, damping: 10 }
47
+ });
48
+
49
+ const opacity = interpolate(progress, [0, delayPerChar], [1, 0], {
50
+ extrapolateLeft: "clamp",
51
+ extrapolateRight: "clamp"
52
+ });
53
+
54
+ return (
55
+ <span
56
+ key={index}
57
+ style={{
58
+ display: "inline-block",
59
+ transformOrigin: "0 100%",
60
+ transform: `translateY(${translateY}em) translateX(${translateX}em) rotateZ(${rotateZ}deg)`,
61
+ opacity
62
+ }}
63
+ >
64
+ {char === " " ? "\u00A0" : char}
65
+ </span>
66
+ );
67
+ };
68
+
69
+ export default RealityIsBrokenAnimationOut;
src/player/animated/text-animated-types/animations-out/sunny-mornings-out.tsx ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { interpolate, spring } from "remotion";
2
+
3
+ const SunnyMorningsAnimationOut = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextOutFrames,
10
+ durationInFrames
11
+ }: {
12
+ char: string;
13
+ index: number;
14
+ frame: number;
15
+ fps: number;
16
+ textLength: number;
17
+ animationTextOutFrames: number;
18
+ durationInFrames: number;
19
+ }) => {
20
+ const exitStart = durationInFrames - animationTextOutFrames;
21
+ const delayPerChar = animationTextOutFrames / textLength;
22
+
23
+ const charExitStart = exitStart + index * delayPerChar;
24
+ const progress = frame - charExitStart;
25
+
26
+ const scale = spring({
27
+ frame: progress,
28
+ fps,
29
+ from: 1,
30
+ to: 0,
31
+ config: { mass: 1, damping: 10 }
32
+ });
33
+
34
+ const opacity = interpolate(progress, [0, delayPerChar], [1, 0], {
35
+ extrapolateLeft: "clamp",
36
+ extrapolateRight: "clamp"
37
+ });
38
+
39
+ return (
40
+ <span
41
+ key={index}
42
+ style={{
43
+ display: "inline-block",
44
+ transform: `scale(${scale})`,
45
+ opacity
46
+ }}
47
+ >
48
+ {char === " " ? " " : char}
49
+ </span>
50
+ );
51
+ };
52
+ export default SunnyMorningsAnimationOut;
src/player/animated/text-animated-types/animations-out/text-animated-out.tsx ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { spring } from "remotion";
2
+
3
+ const AnimatedTextOut = ({
4
+ char,
5
+ index,
6
+ frame,
7
+ fps,
8
+ textLength,
9
+ animationTextOutFrames,
10
+ durationInFrames
11
+ }: {
12
+ char: string;
13
+ index: number;
14
+ frame: number;
15
+ fps: number;
16
+ textLength: number;
17
+ animationTextOutFrames: number;
18
+ durationInFrames: number;
19
+ }) => {
20
+ const startExitFrame = durationInFrames - animationTextOutFrames;
21
+ const delay = (index / textLength) * (durationInFrames - startExitFrame);
22
+
23
+ const opacity = spring({
24
+ frame: frame - startExitFrame - delay,
25
+ fps,
26
+ from: 1,
27
+ to: 0,
28
+ config: { mass: 0.5, damping: 10 }
29
+ });
30
+
31
+ const y = spring({
32
+ frame: frame - startExitFrame - delay,
33
+ fps,
34
+ from: 0,
35
+ to: 50,
36
+ config: { mass: 0.5, damping: 10 }
37
+ });
38
+
39
+ const rotate = spring({
40
+ frame: frame - startExitFrame - delay,
41
+ fps,
42
+ from: 0,
43
+ to: 180,
44
+ config: { mass: 0.5, damping: 12 }
45
+ });
46
+ return (
47
+ <span
48
+ key={index}
49
+ style={{
50
+ display: "inline-block",
51
+ opacity,
52
+ transform: `translateY(${y}px) rotate(${rotate}deg)`
53
+ }}
54
+ >
55
+ {char === " " ? " " : char}
56
+ </span>
57
+ );
58
+ };
59
+
60
+ export default AnimatedTextOut;
src/player/animated/text-animated-types/animations-out/type-writer-out.tsx ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ITextDetails } from "@designcombo/types";
2
+ import { useMemo } from "react";
3
+ import { interpolate } from "remotion";
4
+
5
+ const TypeWriterOut = ({
6
+ animationDuration,
7
+ text,
8
+ details,
9
+ frame,
10
+ durationInFrames
11
+ }: {
12
+ animationDuration: number;
13
+ text: string;
14
+ details: ITextDetails;
15
+ frame: number;
16
+ durationInFrames: number;
17
+ }) => {
18
+ const visibleCharacters = Math.floor(
19
+ interpolate(
20
+ frame,
21
+ [durationInFrames - animationDuration, durationInFrames],
22
+ [text.length, 0],
23
+ { extrapolateRight: "clamp" }
24
+ )
25
+ );
26
+
27
+ const visibleText = useMemo(() => {
28
+ let count = 0;
29
+ return text
30
+ .split(" ")
31
+ .map((word) => {
32
+ if (count + word.length <= visibleCharacters) {
33
+ count += word.length + 1; // Contamos el espacio
34
+ return word;
35
+ }
36
+ if (count < visibleCharacters) {
37
+ const partialWord = word.slice(0, visibleCharacters - count);
38
+ count = visibleCharacters;
39
+ return partialWord;
40
+ }
41
+ return "";
42
+ })
43
+ .join(" ");
44
+ }, [visibleCharacters]);
45
+
46
+ return (
47
+ <div
48
+ style={{
49
+ textAlign: "center"
50
+ }}
51
+ >
52
+ <span
53
+ style={{
54
+ fontSize: details.fontSize
55
+ }}
56
+ >
57
+ {visibleText}
58
+ </span>
59
+ <span
60
+ style={{
61
+ color: "#60a5fa",
62
+ opacity: frame % 15 < 7 ? 1 : 0
63
+ }}
64
+ >
65
+ |
66
+ </span>
67
+ </div>
68
+ );
69
+ };
70
+
71
+ export default TypeWriterOut;
src/player/animated/text-animated.tsx ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ITextDetails } from "@designcombo/types";
2
+ import React, { useMemo } from "react";
3
+ import { useCurrentFrame } from "remotion";
4
+ import AnimatedTextIn from "./text-animated-types/animations-in/text-animated-in";
5
+ import SunnyMorningsAnimationIn from "./text-animated-types/animations-in/sunny-mornings-in";
6
+ import DominoDreamsIn from "./text-animated-types/animations-in/domino-dreams-in";
7
+ import GetThinkersAnimationIn from "./text-animated-types/animations-in/great-thinkers-in";
8
+ import BeatifulQuestionAnimationIn from "./text-animated-types/animations-in/beatiful-question-in";
9
+ import MadeWithLoveAnimationIn from "./text-animated-types/animations-in/made-with-love-in";
10
+ import AnimatedTextOut from "./text-animated-types/animations-out/text-animated-out";
11
+ import SunnyMorningsAnimationOut from "./text-animated-types/animations-out/sunny-mornings-out";
12
+ import DominoDreamsAnimationOut from "./text-animated-types/animations-out/domino-dreams-out";
13
+ import BeatifulQuestionAnimationOut from "./text-animated-types/animations-out/beatiful-question-out";
14
+ import RealityIsBrokenAnimationIn from "./text-animated-types/animations-in/reality-is-broken-in";
15
+ import MadeWithLoveAnimationOut from "./text-animated-types/animations-out/made-with-love-out";
16
+ import RealityIsBrokenAnimationOut from "./text-animated-types/animations-out/reality-is-broken-out";
17
+ import GreatThinkersAnimationOut from "./text-animated-types/animations-out/great-thinkers-out";
18
+ import VogueLetterByLetter from "./text-animated-types/animations-loop/vogue";
19
+ import DragonflyText from "./text-animated-types/animations-loop/dragonfly";
20
+ import BillboardText from "./text-animated-types/animations-loop/billboard";
21
+ import DropAnimationIn from "./text-animated-types/animations-in/drop-in";
22
+ import DescompressAnimationIn from "./text-animated-types/animations-in/descompress-in";
23
+ import DescompressAnimationOut from "./text-animated-types/animations-out/descompress-out";
24
+ import DropAnimationOut from "./text-animated-types/animations-out/drop-out";
25
+ import Heartbeat from "./text-animated-types/animations-loop/heartbeat";
26
+ import Wave from "./text-animated-types/animations-loop/wave";
27
+ import ShakyLettersText from "./text-animated-types/animations-loop/shaky-letters-text";
28
+ import PulseText from "./text-animated-types/animations-loop/pulse";
29
+ import { renderFullTextAnimation } from "./text-animated-full";
30
+
31
+ const animationsIn: { [key: string]: React.FC<any> } = {
32
+ animatedTextIn: AnimatedTextIn,
33
+ sunnyMorningsAnimationIn: SunnyMorningsAnimationIn,
34
+ dominoDreamsIn: DominoDreamsIn,
35
+ greatThinkersAnimationIn: GetThinkersAnimationIn,
36
+ beautifulQuestionsAnimationIn: BeatifulQuestionAnimationIn,
37
+ madeWithLoveAnimationIn: MadeWithLoveAnimationIn,
38
+ realityIsBrokenAnimationIn: RealityIsBrokenAnimationIn,
39
+ dropAnimationIn: DropAnimationIn,
40
+ descompressAnimationIn: DescompressAnimationIn
41
+ };
42
+
43
+ const animationsOut: { [key: string]: React.FC<any> } = {
44
+ animatedTextOut: AnimatedTextOut,
45
+ sunnyMorningsAnimationOut: SunnyMorningsAnimationOut,
46
+ dominoDreamsAnimationOut: DominoDreamsAnimationOut,
47
+ beautifulQuestionsAnimationOut: BeatifulQuestionAnimationOut,
48
+ madeWithLoveAnimationOut: MadeWithLoveAnimationOut,
49
+ realityIsBrokenAnimationOut: RealityIsBrokenAnimationOut,
50
+ greatThinkersAnimationOut: GreatThinkersAnimationOut,
51
+ descompressAnimationOut: DescompressAnimationOut,
52
+ dropAnimationOut: DropAnimationOut
53
+ };
54
+
55
+ const animationsLoop: { [key: string]: React.FC<any> } = {
56
+ vogueAnimationLoop: VogueLetterByLetter,
57
+ dragonFlyAnimationLoop: DragonflyText,
58
+ billboardAnimationLoop: BillboardText,
59
+ heartbeatAnimationLoop: Heartbeat,
60
+ waveAnimationLoop: Wave,
61
+ shakyLettersTextAnimationLoop: ShakyLettersText,
62
+ pulseAnimationLoop: PulseText
63
+ };
64
+
65
+ const getTextLines = (
66
+ text: string,
67
+ width: number,
68
+ fontSize: number
69
+ ): string[] => {
70
+ const canvas = document.createElement("canvas");
71
+ const context = canvas.getContext("2d");
72
+
73
+ if (!context) return [];
74
+
75
+ context.font = `${fontSize}px Arial`;
76
+ const words = text.split(" ");
77
+ let lines: string[] = [];
78
+ let currentLine = "";
79
+
80
+ words.forEach((word) => {
81
+ const testLine = currentLine ? `${currentLine} ${word}` : word;
82
+ const textWidth = context.measureText(testLine).width;
83
+
84
+ if (textWidth > width) {
85
+ lines.push(currentLine);
86
+ currentLine = word;
87
+ } else {
88
+ currentLine = testLine;
89
+ }
90
+ });
91
+
92
+ if (currentLine) lines.push(currentLine);
93
+
94
+ return lines;
95
+ };
96
+
97
+ export const TextAnimated: React.FC<{
98
+ text: string;
99
+ fps: number;
100
+ textAnimationNameIn: string;
101
+ textAnimationNameOut: string;
102
+ textAnimationNameLoop: string;
103
+ details: ITextDetails;
104
+ animationTextInFrames: number;
105
+ animationTextOutFrames: number;
106
+ animationTextLoopFrames: number;
107
+ durationInFrames: number;
108
+ animationFonts: { fontFamily: string; url: string }[];
109
+ }> = ({
110
+ text,
111
+ fps,
112
+ textAnimationNameIn,
113
+ textAnimationNameOut,
114
+ textAnimationNameLoop,
115
+ details,
116
+ animationTextInFrames,
117
+ animationTextOutFrames,
118
+ animationTextLoopFrames,
119
+ durationInFrames,
120
+ animationFonts
121
+ }) => {
122
+ const frame = useCurrentFrame();
123
+ const animInFrom = animationTextInFrames;
124
+ const animOut = durationInFrames - animationTextOutFrames;
125
+ const validAnimIn = textAnimationNameIn ? animInFrom >= frame : false;
126
+ const validAnimOut = textAnimationNameOut ? animOut < frame : false;
127
+ if (!validAnimOut && !validAnimIn) {
128
+ return (
129
+ <div
130
+ style={{
131
+ whiteSpace: "pre-line",
132
+ maxWidth: "100%"
133
+ }}
134
+ >
135
+ {text}
136
+ </div>
137
+ );
138
+ }
139
+
140
+ const lines = getTextLines(text, details.width, details.fontSize);
141
+
142
+ const fullTextAnimation = renderFullTextAnimation({
143
+ frame,
144
+ text,
145
+ details,
146
+ fps,
147
+ durationInFrames,
148
+ animationTextInFrames,
149
+ animationTextOutFrames,
150
+ animationTextLoopFrames,
151
+ animationFonts,
152
+ validAnimIn,
153
+ validAnimOut,
154
+ textAnimationNameIn,
155
+ textAnimationNameOut,
156
+ textAnimationNameLoop
157
+ });
158
+
159
+ if (fullTextAnimation) {
160
+ return fullTextAnimation;
161
+ }
162
+
163
+ const maxTextLengthInLine = lines.reduce(
164
+ (max, line) => Math.max(max, line.length),
165
+ 0
166
+ );
167
+
168
+ const AnimationComponentIn = animationsIn[textAnimationNameIn];
169
+ const AnimationComponentOut = animationsOut[textAnimationNameOut];
170
+ const AnimationComponentLoop = animationsLoop[textAnimationNameLoop];
171
+
172
+ return (
173
+ <>
174
+ {lines.map((line, rowIndex) => (
175
+ <div key={rowIndex}>
176
+ {line.split("").map((char, index) => {
177
+ if (validAnimIn && AnimationComponentIn) {
178
+ return (
179
+ <AnimationComponentIn
180
+ key={index}
181
+ char={char}
182
+ index={index}
183
+ frame={frame}
184
+ textLength={maxTextLengthInLine}
185
+ fps={fps}
186
+ animationTextInFrames={animationTextInFrames}
187
+ details={details}
188
+ />
189
+ );
190
+ }
191
+ if (validAnimOut && AnimationComponentOut) {
192
+ return (
193
+ <AnimationComponentOut
194
+ key={index}
195
+ char={char}
196
+ index={index}
197
+ frame={frame}
198
+ textLength={maxTextLengthInLine}
199
+ fps={fps}
200
+ animationTextOutFrames={animationTextOutFrames}
201
+ durationInFrames={durationInFrames}
202
+ details={details}
203
+ />
204
+ );
205
+ }
206
+ if (textAnimationNameLoop && !validAnimIn && !validAnimOut) {
207
+ return (
208
+ <AnimationComponentLoop
209
+ key={index}
210
+ char={char}
211
+ index={index}
212
+ frame={frame}
213
+ textLength={maxTextLengthInLine}
214
+ fps={fps}
215
+ animationTextLoopFrames={animationTextLoopFrames}
216
+ details={details}
217
+ />
218
+ );
219
+ }
220
+ return <span key={index}>{char}</span>;
221
+ })}
222
+ </div>
223
+ ))}
224
+ </>
225
+ );
226
+ };
src/player/animated/types.ts ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // types.ts
2
+
3
+ export interface Animation {
4
+ property: string;
5
+ from: number;
6
+ to: number;
7
+ durationInFrames: number;
8
+ ease: (t: number) => number;
9
+ delay?: number;
10
+ previewUrl?: string;
11
+ name?: string;
12
+ details?: {
13
+ fonts?: {
14
+ fontFamily: string;
15
+ url: string;
16
+ }[];
17
+ };
18
+ }
19
+
20
+ export interface StaggerConfig {
21
+ amount: number;
22
+ overlap?: number; // 0-1, where 1 means full overlap
23
+ }
24
+
25
+ export interface AnimationConfig {
26
+ in?: Animation | Animation[];
27
+ out?: Animation | Animation[];
28
+ stagger?: StaggerConfig;
29
+ }
30
+
31
+ export interface AnimatedElementProps {
32
+ animationIn?: Animation | Animation[];
33
+ animationOut?: Animation | Animation[];
34
+ durationInFrames: number;
35
+ children: React.ReactNode;
36
+ className?: string;
37
+ }
38
+
39
+ export interface AnimatedTextProps {
40
+ children: string;
41
+ durationInFrames: number;
42
+ wordAnimation?: AnimationConfig;
43
+ letterAnimation?: AnimationConfig;
44
+ className?: string;
45
+ }
46
+
47
+ // You might want to export these utility types as well
48
+ export type CombineAnimations = (
49
+ ...animations: (Animation | Animation[] | undefined)[]
50
+ ) => Animation[];
51
+
52
+ export type CreateStaggeredAnimations = (
53
+ animations: Animation | Animation[] | undefined,
54
+ count: number,
55
+ stagger: StaggerConfig,
56
+ durationInFrames: number,
57
+ isOut: boolean
58
+ ) => Animation[];
src/player/base-sequence.tsx ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { ISize, ITrackItem } from "@designcombo/types";
2
+ import { AbsoluteFill, Sequence } from "remotion";
3
+ import { calculateFrames } from "../utils/frames";
4
+ import { calculateContainerStyles } from "./styles";
5
+ import { TransitionSeries } from "@designcombo/transitions";
6
+
7
+ export interface SequenceItemOptions {
8
+ handleTextChange?: (id: string, text: string) => void;
9
+ fps: number;
10
+ editableTextId?: string | null;
11
+ currentTime?: number;
12
+ zIndex?: number;
13
+ onTextBlur?: (id: string, text: string) => void;
14
+ size?: ISize;
15
+ frame?: number;
16
+ isTransition?: boolean;
17
+ }
18
+
19
+ export const BaseSequence = ({
20
+ item,
21
+ options,
22
+ children
23
+ }: {
24
+ item: ITrackItem;
25
+ options: SequenceItemOptions;
26
+ children: React.ReactNode;
27
+ }) => {
28
+ const { details } = item as ITrackItem;
29
+ const { fps, isTransition } = options;
30
+ const { from, durationInFrames } = calculateFrames(
31
+ {
32
+ from: item.display.from,
33
+ to: item.display.to
34
+ },
35
+ fps
36
+ );
37
+ const crop = details.crop || {
38
+ x: 0,
39
+ y: 0,
40
+ width: item.details.width,
41
+ height: item.details.height
42
+ };
43
+
44
+ const background =
45
+ details?.background?.type === "color"
46
+ ? details?.background?.value
47
+ : typeof details?.background === "string"
48
+ ? details?.background
49
+ : "transparent";
50
+
51
+ if (isTransition) {
52
+ return (
53
+ <TransitionSeries.Sequence
54
+ key={item.id}
55
+ durationInFrames={durationInFrames}
56
+ style={{ pointerEvents: "none" }}
57
+ >
58
+ <AbsoluteFill
59
+ id={item.id}
60
+ data-track-item="transition-element"
61
+ className={`designcombo-scene-item id-${item.id} designcombo-scene-item-type-${item.type}`}
62
+ style={calculateContainerStyles(details, crop, { background })}
63
+ >
64
+ {children}
65
+ </AbsoluteFill>
66
+ </TransitionSeries.Sequence>
67
+ );
68
+ }
69
+
70
+ return (
71
+ <Sequence
72
+ key={item.id}
73
+ from={from}
74
+ durationInFrames={durationInFrames || 1 / fps}
75
+ style={{
76
+ pointerEvents: "none"
77
+ }}
78
+ >
79
+ <AbsoluteFill
80
+ id={item.id}
81
+ data-track-item="transition-element"
82
+ className={`designcombo-scene-item id-${item.id} designcombo-scene-item-type-${item.type}`}
83
+ style={calculateContainerStyles(
84
+ details,
85
+ crop,
86
+ {
87
+ background,
88
+ pointerEvents: item.type === "audio" ? "none" : "auto",
89
+ overflow:
90
+ item.type !== "caption" && item.type !== "text"
91
+ ? "hidden"
92
+ : "visible"
93
+ },
94
+ item.type
95
+ )}
96
+ >
97
+ {children}
98
+ </AbsoluteFill>
99
+ </Sequence>
100
+ );
101
+ };