@evatril/video-templates 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +14 -0
- package/public/Fonts/DancingScript-VariableFont_wght.ttf +0 -0
- package/public/Fonts/GreatVibes-Regular.ttf +0 -0
- package/public/Fonts/PlayfairDisplay-Italic-VariableFont_wght.ttf +0 -0
- package/public/video-images/20012026-bg.png +0 -0
- package/public/video-images/20012026-bride.png +0 -0
- package/public/video-images/20012026-butterfly.png +0 -0
- package/public/video-images/20012026-couple-walk.png +0 -0
- package/public/video-images/20012026-curtain-floral.png +0 -0
- package/public/video-images/20012026-floral-left.png +0 -0
- package/public/video-images/20012026-floral-right.png +0 -0
- package/public/video-images/20012026-groom.png +0 -0
- package/public/video-images/20012026-opening-gate.png +0 -0
- package/public/video-images/20012026-peacock.png +0 -0
- package/public/video-images/20012026-tree-left.png +0 -0
- package/public/video-images/20012026-tree-right.png +0 -0
- package/public/video-images/20012026-wedding-gate.png +0 -0
- package/public/video-images/wedding.mp3 +0 -0
- package/src/Invitations/Elements/Butterflies20012026.jsx +70 -0
- package/src/Invitations/Elements/CoupleWalk20012026.jsx +74 -0
- package/src/Invitations/Elements/FlowersSide20012026.jsx +143 -0
- package/src/Invitations/Elements/GroomBrideLoveScene20012026.jsx +163 -0
- package/src/Invitations/Elements/InkSmokeTransition20012026.jsx +72 -0
- package/src/Invitations/Elements/OpeningGate20012026.jsx +59 -0
- package/src/Invitations/Elements/PeacockDance20012026.jsx +68 -0
- package/src/Invitations/Elements/SideTrees20012026.jsx +104 -0
- package/src/Invitations/Elements/SmoothRevealFromTop.jsx +32 -0
- package/src/Invitations/Frames/F20012026_01.jsx +180 -0
- package/src/Invitations/Frames/F20012026_02.jsx +311 -0
- package/src/Invitations/Frames/F20012026_03.jsx +317 -0
- package/src/Invitations/Themes/T20012026_01.jsx +125 -0
- package/src/compositions.jsx +19 -0
- package/src/fonts/index.js +3 -0
- package/src/fonts/registerFonts.js +46 -0
- package/src/index.js +2 -0
- package/src/remotionRoot.jsx +5 -0
package/package.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@evatril/video-templates",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"remotion": {
|
|
7
|
+
"entryPoint": "src/remotionRoot.jsx"
|
|
8
|
+
},
|
|
9
|
+
"peerDependencies": {
|
|
10
|
+
"react": ">=18",
|
|
11
|
+
"react-dom": ">=18",
|
|
12
|
+
"remotion": "^4.0.0"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Img, interpolate, staticFile } from "remotion";
|
|
3
|
+
|
|
4
|
+
export const Butterflies20012026 = ({ frame, fps, width, height }) => {
|
|
5
|
+
const GLOBAL_DELAY = fps * 2;
|
|
6
|
+
const butterflies = [
|
|
7
|
+
{ sx: 0.1, sy: 0.9, ex: 0.8, ey: 0.2, delay: 0 },
|
|
8
|
+
{ sx: 0.9, sy: 0.85, ex: 0.2, ey: 0.1, delay: 20 },
|
|
9
|
+
{ sx: 0.3, sy: 1.0, ex: 0.7, ey: 0.3, delay: 40 },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<>
|
|
14
|
+
{butterflies.map((b, i) => {
|
|
15
|
+
const localFrame = frame - GLOBAL_DELAY - b.delay;
|
|
16
|
+
const progress = interpolate(
|
|
17
|
+
localFrame,
|
|
18
|
+
[0, fps * 6],
|
|
19
|
+
[0, 1],
|
|
20
|
+
{
|
|
21
|
+
extrapolateLeft: "clamp",
|
|
22
|
+
extrapolateRight: "clamp",
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const x = interpolate(progress, [0, 1], [
|
|
27
|
+
b.sx * width,
|
|
28
|
+
b.ex * width,
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const y =
|
|
32
|
+
interpolate(progress, [0, 1], [
|
|
33
|
+
b.sy * height,
|
|
34
|
+
b.ey * height,
|
|
35
|
+
]) +
|
|
36
|
+
Math.sin(frame / 10 + i * 20) * 25;
|
|
37
|
+
|
|
38
|
+
const scale = interpolate(
|
|
39
|
+
progress,
|
|
40
|
+
[0, 0.1, 0.9, 1],
|
|
41
|
+
[0, 1, 1, 0.6]
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const opacity = progress > 0.05 && progress < 0.95 ? 1 : 0;
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<Img
|
|
48
|
+
key={i}
|
|
49
|
+
src={staticFile("video-images/20012026-butterfly.png")}
|
|
50
|
+
style={{
|
|
51
|
+
position: "absolute",
|
|
52
|
+
left: x,
|
|
53
|
+
top: y,
|
|
54
|
+
width: 120,
|
|
55
|
+
height: 120,
|
|
56
|
+
opacity,
|
|
57
|
+
transform: `
|
|
58
|
+
translate(-50%, -50%)
|
|
59
|
+
scale(${scale})
|
|
60
|
+
rotate(${Math.sin(localFrame / 15 + i) * 15}deg)
|
|
61
|
+
`,
|
|
62
|
+
filter: "drop-shadow(0 0 6px rgba(0,255,255,0.45))",
|
|
63
|
+
pointerEvents: "none",
|
|
64
|
+
}}
|
|
65
|
+
/>
|
|
66
|
+
);
|
|
67
|
+
})}
|
|
68
|
+
</>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Img,
|
|
4
|
+
staticFile,
|
|
5
|
+
useCurrentFrame,
|
|
6
|
+
useVideoConfig,
|
|
7
|
+
interpolate,
|
|
8
|
+
Easing,
|
|
9
|
+
} from "remotion";
|
|
10
|
+
|
|
11
|
+
export const CoupleWalk20012026 = () => {
|
|
12
|
+
const frame = useCurrentFrame();
|
|
13
|
+
const { fps, height } = useVideoConfig();
|
|
14
|
+
|
|
15
|
+
/* -----------------------------⏳ WALK SETTINGS ------------------------------*/
|
|
16
|
+
const delaySeconds = 0.5;
|
|
17
|
+
const walkDurationSeconds = 5;
|
|
18
|
+
const delayFrames = fps * delaySeconds;
|
|
19
|
+
const walkFrames = fps * walkDurationSeconds;
|
|
20
|
+
const localFrame = frame - delayFrames;
|
|
21
|
+
/* --------🚶 WALK FROM BOTTOM → UP (Bottom-center anchor)--------*/
|
|
22
|
+
const walkY = interpolate(
|
|
23
|
+
localFrame,
|
|
24
|
+
[0, walkFrames],
|
|
25
|
+
[height + 600, height - 950],
|
|
26
|
+
{
|
|
27
|
+
extrapolateLeft: "clamp",
|
|
28
|
+
extrapolateRight: "clamp",
|
|
29
|
+
easing: Easing.out(Easing.cubic),
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
const isWalking = localFrame >= 0 && localFrame <= walkFrames;
|
|
33
|
+
|
|
34
|
+
/* ------- ⬆️⬇️ SUBTLE BOUNCE -------*/
|
|
35
|
+
const bounce = isWalking
|
|
36
|
+
? Math.sin(localFrame / 10) * 3
|
|
37
|
+
: 0;
|
|
38
|
+
|
|
39
|
+
/* ------- ↔️ NATURAL SWAY ------------*/
|
|
40
|
+
const sway = isWalking
|
|
41
|
+
? Math.sin(localFrame / 14) * 2
|
|
42
|
+
: 0;
|
|
43
|
+
|
|
44
|
+
/* -------- 👣 FOOTSTEP SCALE ----------*/
|
|
45
|
+
const stepScale = isWalking
|
|
46
|
+
? 1 + Math.sin(localFrame / 12) * 0.015
|
|
47
|
+
: 1;
|
|
48
|
+
return (
|
|
49
|
+
<div
|
|
50
|
+
style={{
|
|
51
|
+
flex: 1,
|
|
52
|
+
position: "relative",
|
|
53
|
+
overflow: "hidden",
|
|
54
|
+
}}
|
|
55
|
+
>
|
|
56
|
+
|
|
57
|
+
{/* 👰🤵 COUPLE (BOTTOM-CENTER) */}
|
|
58
|
+
<Img
|
|
59
|
+
src={staticFile("video-images/20012026-couple-walk.png")}
|
|
60
|
+
style={{
|
|
61
|
+
position: "absolute",
|
|
62
|
+
left: "50%",
|
|
63
|
+
transform: `
|
|
64
|
+
translateX(-50%)
|
|
65
|
+
translateY(${walkY + bounce}px)
|
|
66
|
+
translateX(${sway}px)
|
|
67
|
+
scale(${stepScale})
|
|
68
|
+
`,
|
|
69
|
+
width: "60%",
|
|
70
|
+
}}
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Img,
|
|
4
|
+
staticFile,
|
|
5
|
+
useCurrentFrame,
|
|
6
|
+
useVideoConfig,
|
|
7
|
+
interpolate,
|
|
8
|
+
Easing,
|
|
9
|
+
} from "remotion";
|
|
10
|
+
|
|
11
|
+
/* 🌸 FALLING EMOJI FLOWER – MULTI LINE */
|
|
12
|
+
const FallingEmojiFlower = ({ index, row = 0, startAfter = 6 }) => {
|
|
13
|
+
const frame = useCurrentFrame();
|
|
14
|
+
const { height, width, fps } = useVideoConfig();
|
|
15
|
+
|
|
16
|
+
const delayFrames = fps * startAfter;
|
|
17
|
+
|
|
18
|
+
/* 🌸 CENTER STRIP */
|
|
19
|
+
const stripWidth = width * 0.28;
|
|
20
|
+
const baseX =
|
|
21
|
+
width / 2 - stripWidth / 2 + ((index * 50) % stripWidth);
|
|
22
|
+
|
|
23
|
+
/* 🌸 ROW OFFSET (2–3 LINES) */
|
|
24
|
+
const rowOffsetY = row * 60;
|
|
25
|
+
|
|
26
|
+
const individualDelay = index * 10 + row * 15;
|
|
27
|
+
const duration = fps * 4;
|
|
28
|
+
|
|
29
|
+
const localFrame = frame - delayFrames - individualDelay;
|
|
30
|
+
|
|
31
|
+
const progress = interpolate(
|
|
32
|
+
localFrame,
|
|
33
|
+
[0, duration],
|
|
34
|
+
[0, 1],
|
|
35
|
+
{
|
|
36
|
+
extrapolateLeft: "clamp",
|
|
37
|
+
extrapolateRight: "clamp",
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const translateY = interpolate(
|
|
42
|
+
progress,
|
|
43
|
+
[0, 1],
|
|
44
|
+
[-80 + rowOffsetY, height + 80]
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const sway =
|
|
48
|
+
progress < 1
|
|
49
|
+
? Math.sin(localFrame / 15) * 14
|
|
50
|
+
: 0;
|
|
51
|
+
|
|
52
|
+
const rotate = progress * 360;
|
|
53
|
+
|
|
54
|
+
// ❌ Do not render before start or after finish
|
|
55
|
+
if (localFrame < 0 || localFrame > duration) return null;
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div
|
|
59
|
+
style={{
|
|
60
|
+
position: "absolute",
|
|
61
|
+
left: baseX,
|
|
62
|
+
top: translateY,
|
|
63
|
+
fontSize: 44,
|
|
64
|
+
opacity: 0.85,
|
|
65
|
+
transform: `translateX(${sway}px) rotate(${rotate}deg)`,
|
|
66
|
+
pointerEvents: "none",
|
|
67
|
+
userSelect: "none",
|
|
68
|
+
}}
|
|
69
|
+
>
|
|
70
|
+
{["🌸", "🌺"][index % 2]}
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const FlowersSide20012026 = ({ startAfter = 1 }) => {
|
|
76
|
+
const frame = useCurrentFrame();
|
|
77
|
+
const { fps } = useVideoConfig();
|
|
78
|
+
|
|
79
|
+
const delayFrames = fps * startAfter;
|
|
80
|
+
const revealDuration = fps * 2.5; // ⏱ 2 seconds
|
|
81
|
+
|
|
82
|
+
const revealProgress = interpolate(
|
|
83
|
+
frame - delayFrames,
|
|
84
|
+
[0, revealDuration],
|
|
85
|
+
[0, 1],
|
|
86
|
+
{
|
|
87
|
+
extrapolateLeft: "clamp",
|
|
88
|
+
extrapolateRight: "clamp",
|
|
89
|
+
easing: Easing.out(Easing.cubic),
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<>
|
|
95
|
+
{/* 🌸 ONE-TIME FLOWER FALL (AFTER 2s) */}
|
|
96
|
+
{[0, 1, 2].map((row) =>
|
|
97
|
+
Array.from({ length: 5 }).map((_, i) => (
|
|
98
|
+
<FallingEmojiFlower
|
|
99
|
+
key={`row-${row}-${i}`}
|
|
100
|
+
index={i}
|
|
101
|
+
row={row}
|
|
102
|
+
startAfter={6}
|
|
103
|
+
/>
|
|
104
|
+
))
|
|
105
|
+
)}
|
|
106
|
+
{/* 🌸 LEFT FLOWER DECOR */}
|
|
107
|
+
<Img
|
|
108
|
+
src={staticFile("video-images/20012026-floral-left.png")}
|
|
109
|
+
style={{
|
|
110
|
+
position: "absolute",
|
|
111
|
+
left: 0,
|
|
112
|
+
bottom: 370,
|
|
113
|
+
width: "100%",
|
|
114
|
+
opacity: revealProgress,
|
|
115
|
+
transform: `
|
|
116
|
+
translateX(${interpolate(revealProgress, [0, 1], [-120, -30])}px)
|
|
117
|
+
scale(${interpolate(revealProgress, [0, 1], [0.96, 1])})
|
|
118
|
+
`,
|
|
119
|
+
pointerEvents: "none",
|
|
120
|
+
}}
|
|
121
|
+
/>
|
|
122
|
+
{/* 🌸 RIGHT FLOWER DECOR */}
|
|
123
|
+
<Img
|
|
124
|
+
src={staticFile("video-images/20012026-floral-right.png")}
|
|
125
|
+
style={{
|
|
126
|
+
position: "absolute",
|
|
127
|
+
right: 0,
|
|
128
|
+
bottom: 370,
|
|
129
|
+
width: "100%",
|
|
130
|
+
opacity: revealProgress,
|
|
131
|
+
transform: `
|
|
132
|
+
translateX(${interpolate(revealProgress, [0, 1], [120, 30])}px)
|
|
133
|
+
scale(${interpolate(revealProgress, [0, 1], [0.96, 1])})
|
|
134
|
+
`,
|
|
135
|
+
pointerEvents: "none",
|
|
136
|
+
}}
|
|
137
|
+
/>
|
|
138
|
+
|
|
139
|
+
</>
|
|
140
|
+
);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Img,
|
|
4
|
+
staticFile,
|
|
5
|
+
useCurrentFrame,
|
|
6
|
+
useVideoConfig,
|
|
7
|
+
interpolate,
|
|
8
|
+
Easing,
|
|
9
|
+
} from "remotion";
|
|
10
|
+
|
|
11
|
+
export const GroomBrideLoveScene20012026 = ({ startAfter = 3.5}) => {
|
|
12
|
+
const frame = useCurrentFrame();
|
|
13
|
+
const { fps, width } = useVideoConfig();
|
|
14
|
+
|
|
15
|
+
/* ---------------- TIMING ---------------- */
|
|
16
|
+
const showDelay = fps * startAfter; // when both appear
|
|
17
|
+
const walkDelay = showDelay + fps * 0.1; // groom starts walking after pause
|
|
18
|
+
const walkDuration = fps * 3.5; // slow cinematic walk
|
|
19
|
+
|
|
20
|
+
if (frame < showDelay) return null;
|
|
21
|
+
|
|
22
|
+
/* ---------------- OPACITY (BOTH SHOW SAME TIME) ---------------- */
|
|
23
|
+
const opacity = interpolate(
|
|
24
|
+
frame,
|
|
25
|
+
[showDelay, showDelay + fps * 0.5],
|
|
26
|
+
[0, 1],
|
|
27
|
+
{ extrapolateLeft: "clamp" }
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
/* ---------------- WALK FRAME ---------------- */
|
|
31
|
+
const walkFrame = Math.max(0, frame - walkDelay);
|
|
32
|
+
const progress = interpolate(
|
|
33
|
+
walkFrame,
|
|
34
|
+
[0, walkDuration],
|
|
35
|
+
[0, 1],
|
|
36
|
+
{
|
|
37
|
+
extrapolateLeft: "clamp",
|
|
38
|
+
extrapolateRight: "clamp",
|
|
39
|
+
easing: Easing.inOut(Easing.cubic),
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
/* ---------------- POSITIONS ---------------- */
|
|
44
|
+
const brideX = width - 390; // 👰 fixed right
|
|
45
|
+
const groomStartX = -140; // 🤵 visible at left initially
|
|
46
|
+
const groomEndX = brideX - 260;
|
|
47
|
+
|
|
48
|
+
const groomX = interpolate(
|
|
49
|
+
progress,
|
|
50
|
+
[0, 1],
|
|
51
|
+
[groomStartX, groomEndX],
|
|
52
|
+
{
|
|
53
|
+
easing: Easing.inOut(Easing.cubic),
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
/* ---------------- 3D WALK MOTION ---------------- */
|
|
58
|
+
const footLift = Math.abs(Math.sin(walkFrame / 14)) * 8;
|
|
59
|
+
const bodySway = Math.sin(walkFrame / 26) * 6;
|
|
60
|
+
const depthScale = 1 + Math.sin(walkFrame / 18) * 0.03;
|
|
61
|
+
const rotateZ = Math.sin(walkFrame / 30) * 1.2;
|
|
62
|
+
|
|
63
|
+
/* ---------------- BRIDE TURN (SAFE FLIP) ---------------- */
|
|
64
|
+
const meetFrame = walkDelay + walkDuration;
|
|
65
|
+
const brideTurnDuration = fps * 0.6;
|
|
66
|
+
const brideFlip = interpolate(
|
|
67
|
+
frame,
|
|
68
|
+
[meetFrame, meetFrame + brideTurnDuration],
|
|
69
|
+
[1, -1], // RIGHT → LEFT
|
|
70
|
+
{
|
|
71
|
+
extrapolateLeft: "clamp",
|
|
72
|
+
extrapolateRight: "clamp",
|
|
73
|
+
easing: Easing.inOut(Easing.cubic),
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
/* ---------------- LOVE EMOJI ---------------- */
|
|
78
|
+
const loveStart = meetFrame + brideTurnDuration;
|
|
79
|
+
return (
|
|
80
|
+
<>
|
|
81
|
+
{/* 🤵 GROOM (SHOW → PAUSE → WALK) */}
|
|
82
|
+
<Img
|
|
83
|
+
src={staticFile("video-images/20012026-groom.png")}
|
|
84
|
+
style={{
|
|
85
|
+
position: "absolute",
|
|
86
|
+
bottom: 0,
|
|
87
|
+
width: "40%",
|
|
88
|
+
opacity,
|
|
89
|
+
transform: `
|
|
90
|
+
translateX(${groomX + bodySway}px)
|
|
91
|
+
translateY(${-footLift}px)
|
|
92
|
+
scale(${depthScale})
|
|
93
|
+
rotateZ(${rotateZ}deg)
|
|
94
|
+
`,
|
|
95
|
+
transformOrigin: "bottom center",
|
|
96
|
+
}}
|
|
97
|
+
/>
|
|
98
|
+
|
|
99
|
+
{/* 👰 BRIDE (FIXED, SHOWS SAME TIME) */}
|
|
100
|
+
<Img
|
|
101
|
+
src={staticFile("video-images/20012026-bride.png")}
|
|
102
|
+
style={{
|
|
103
|
+
position: "absolute",
|
|
104
|
+
bottom: 0,
|
|
105
|
+
width: "40%",
|
|
106
|
+
opacity,
|
|
107
|
+
transform: `
|
|
108
|
+
translateX(${brideX}px)
|
|
109
|
+
scaleX(${brideFlip})
|
|
110
|
+
`,
|
|
111
|
+
transformOrigin: "bottom center",
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
114
|
+
{/* ❤️ MULTIPLE FLOATING LOVE EMOJIS */}
|
|
115
|
+
{frame > loveStart &&
|
|
116
|
+
Array.from({ length: 16 }).map((_, i) => {
|
|
117
|
+
const emojiDelay = i * 8;
|
|
118
|
+
const emojiFrame = frame - loveStart - emojiDelay;
|
|
119
|
+
|
|
120
|
+
if (emojiFrame < 0) return null;
|
|
121
|
+
|
|
122
|
+
const floatY = interpolate(
|
|
123
|
+
emojiFrame,
|
|
124
|
+
[0, fps * 2.2],
|
|
125
|
+
[0, -240],
|
|
126
|
+
{ extrapolateRight: "clamp" }
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const emojiOpacity = interpolate(
|
|
130
|
+
emojiFrame,
|
|
131
|
+
[0, fps * 0.4, fps * 1.8],
|
|
132
|
+
[0, 1, 0],
|
|
133
|
+
{ extrapolateRight: "clamp" }
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
const spreadX =
|
|
137
|
+
brideX + 60 + Math.sin(i * 35) * 100;
|
|
138
|
+
|
|
139
|
+
const scale = 0.7 + (i % 5) * 0.12;
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<div
|
|
143
|
+
key={i}
|
|
144
|
+
style={{
|
|
145
|
+
position: "absolute",
|
|
146
|
+
bottom: "30%",
|
|
147
|
+
left: spreadX,
|
|
148
|
+
fontSize: 66,
|
|
149
|
+
opacity: emojiOpacity,
|
|
150
|
+
transform: `
|
|
151
|
+
translateY(${floatY}px)
|
|
152
|
+
scale(${scale})
|
|
153
|
+
`,
|
|
154
|
+
pointerEvents: "none",
|
|
155
|
+
}}
|
|
156
|
+
>
|
|
157
|
+
💖
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
})}
|
|
161
|
+
</>
|
|
162
|
+
);
|
|
163
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
AbsoluteFill,
|
|
4
|
+
useCurrentFrame,
|
|
5
|
+
useVideoConfig,
|
|
6
|
+
interpolate,
|
|
7
|
+
} from "remotion";
|
|
8
|
+
|
|
9
|
+
export const InkSmokeTransition20012026 = () => {
|
|
10
|
+
const frame = useCurrentFrame();
|
|
11
|
+
const { fps, width, height } = useVideoConfig();
|
|
12
|
+
|
|
13
|
+
const duration = fps * 1.2;
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<AbsoluteFill
|
|
17
|
+
style={{
|
|
18
|
+
pointerEvents: "none",
|
|
19
|
+
overflow: "hidden",
|
|
20
|
+
}}
|
|
21
|
+
>
|
|
22
|
+
{Array.from({ length: 12 }).map((_, i) => {
|
|
23
|
+
const delay = i * 3;
|
|
24
|
+
const localFrame = Math.max(0, frame - delay);
|
|
25
|
+
|
|
26
|
+
const scale = interpolate(
|
|
27
|
+
localFrame,
|
|
28
|
+
[0, duration],
|
|
29
|
+
[0.3, 3.4],
|
|
30
|
+
{ extrapolateRight: "clamp" }
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const opacity = interpolate(
|
|
34
|
+
localFrame,
|
|
35
|
+
[0, duration * 0.4, duration],
|
|
36
|
+
[0, 0.8, 0],
|
|
37
|
+
{ extrapolateRight: "clamp" }
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
/* 🔑 CENTER-OUT POSITIONING */
|
|
41
|
+
const angle = (i / 12) * Math.PI * 2; // circular spread
|
|
42
|
+
const radius = 120; // initial spread radius
|
|
43
|
+
|
|
44
|
+
const offsetX = Math.cos(angle) * radius;
|
|
45
|
+
const offsetY = Math.sin(angle) * radius;
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div
|
|
49
|
+
key={i}
|
|
50
|
+
style={{
|
|
51
|
+
position: "absolute",
|
|
52
|
+
width: 320 + i * 40,
|
|
53
|
+
height: 320 + i * 40,
|
|
54
|
+
borderRadius: "50%",
|
|
55
|
+
background:
|
|
56
|
+
"radial-gradient(circle, rgba(255,210,220,0.9), rgba(255,255,255,0.4))",
|
|
57
|
+
|
|
58
|
+
/* 🎯 START FROM CENTER */
|
|
59
|
+
left: width / 2 + offsetX - (320 + i * 40) / 2,
|
|
60
|
+
top: height / 2 + offsetY - (320 + i * 40) / 2,
|
|
61
|
+
|
|
62
|
+
transform: `scale(${scale})`,
|
|
63
|
+
opacity,
|
|
64
|
+
filter: "blur(35px)",
|
|
65
|
+
mixBlendMode: "screen",
|
|
66
|
+
}}
|
|
67
|
+
/>
|
|
68
|
+
);
|
|
69
|
+
})}
|
|
70
|
+
</AbsoluteFill>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Img, interpolate, Easing, staticFile } from "remotion";
|
|
3
|
+
|
|
4
|
+
export const OpeningGate20012026 = ({ frame, fps }) => {
|
|
5
|
+
// ⏱ 1 second gate opening
|
|
6
|
+
const OPEN_DURATION = fps * 1;
|
|
7
|
+
|
|
8
|
+
const progress = interpolate(
|
|
9
|
+
frame,
|
|
10
|
+
[0, OPEN_DURATION],
|
|
11
|
+
[0, 1],
|
|
12
|
+
{
|
|
13
|
+
extrapolateLeft: "clamp",
|
|
14
|
+
extrapolateRight: "clamp",
|
|
15
|
+
easing: Easing.out(Easing.ease),
|
|
16
|
+
}
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const leftRotate = interpolate(progress, [0, 1], [0, -90]);
|
|
20
|
+
const rightRotate = interpolate(progress, [0, 1], [0, 90]);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
style={{
|
|
25
|
+
position: "absolute",
|
|
26
|
+
inset: 0,
|
|
27
|
+
overflow: "hidden",
|
|
28
|
+
zIndex: 9999,
|
|
29
|
+
pointerEvents: "none",
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
{/* 🚪 LEFT DOOR */}
|
|
33
|
+
<Img
|
|
34
|
+
src={staticFile("video-images/20012026-opening-gate.png")}
|
|
35
|
+
style={{
|
|
36
|
+
position: "absolute",
|
|
37
|
+
bottom: 0,
|
|
38
|
+
left: 0,
|
|
39
|
+
width: "100%",
|
|
40
|
+
transformOrigin: "left center",
|
|
41
|
+
transform: `perspective(9000px) rotateY(${leftRotate}deg)`,
|
|
42
|
+
}}
|
|
43
|
+
/>
|
|
44
|
+
|
|
45
|
+
{/* 🚪 RIGHT DOOR */}
|
|
46
|
+
<Img
|
|
47
|
+
src={staticFile("video-images/20012026-opening-gate.png")}
|
|
48
|
+
style={{
|
|
49
|
+
position: "absolute",
|
|
50
|
+
bottom: 0,
|
|
51
|
+
right: 0,
|
|
52
|
+
width: "100%",
|
|
53
|
+
transformOrigin: "right center",
|
|
54
|
+
transform: `perspective(9000px) rotateY(${rightRotate}deg)`,
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
};
|