add marketing movies
This commit is contained in:
788
feels-promo/src/ConceptH-MoodHeist.tsx
Normal file
788
feels-promo/src/ConceptH-MoodHeist.tsx
Normal file
@@ -0,0 +1,788 @@
|
||||
import {
|
||||
AbsoluteFill,
|
||||
Img,
|
||||
staticFile,
|
||||
useCurrentFrame,
|
||||
useVideoConfig,
|
||||
interpolate,
|
||||
spring,
|
||||
Sequence,
|
||||
Easing,
|
||||
} from "remotion";
|
||||
|
||||
// Cinematic letterbox bars
|
||||
const LetterBox: React.FC = () => (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: 120,
|
||||
background: "black",
|
||||
zIndex: 100,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: 120,
|
||||
background: "black",
|
||||
zIndex: 100,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
// Scan lines for that heist movie feel
|
||||
const ScanLines: React.FC<{ opacity?: number }> = ({ opacity = 0.1 }) => {
|
||||
const frame = useCurrentFrame();
|
||||
const offset = (frame * 2) % 4;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: `repeating-linear-gradient(
|
||||
0deg,
|
||||
transparent,
|
||||
transparent 2px,
|
||||
rgba(0,0,0,${opacity}) 2px,
|
||||
rgba(0,0,0,${opacity}) 4px
|
||||
)`,
|
||||
transform: `translateY(${offset}px)`,
|
||||
pointerEvents: "none",
|
||||
zIndex: 50,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
// Glitch effect text
|
||||
const GlitchText: React.FC<{
|
||||
children: string;
|
||||
style?: React.CSSProperties;
|
||||
}> = ({ children, style }) => {
|
||||
const frame = useCurrentFrame();
|
||||
const glitchOffset = Math.sin(frame * 0.5) * 2;
|
||||
const shouldGlitch = frame % 30 < 3;
|
||||
|
||||
return (
|
||||
<div style={{ position: "relative", ...style }}>
|
||||
{shouldGlitch && (
|
||||
<>
|
||||
<span
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: glitchOffset,
|
||||
color: "#ff0000",
|
||||
opacity: 0.8,
|
||||
clipPath: "inset(10% 0 60% 0)",
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
position: "absolute",
|
||||
left: -glitchOffset,
|
||||
color: "#00ffff",
|
||||
opacity: 0.8,
|
||||
clipPath: "inset(60% 0 10% 0)",
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
<span style={{ position: "relative" }}>{children}</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Scene 1: The Setup - "They took something from you"
|
||||
const SetupScene: React.FC = () => {
|
||||
const frame = useCurrentFrame();
|
||||
const { fps } = useVideoConfig();
|
||||
|
||||
const fadeIn = interpolate(frame, [0, fps * 0.5], [0, 1], {
|
||||
extrapolateRight: "clamp",
|
||||
});
|
||||
|
||||
const textReveal = interpolate(frame, [fps * 0.5, fps * 2], [0, 1], {
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
});
|
||||
|
||||
const typewriterLength = Math.floor(textReveal * 28);
|
||||
const fullText = "They took something from you";
|
||||
const displayText = fullText.slice(0, typewriterLength);
|
||||
|
||||
// Flicker effect
|
||||
const flicker = frame % 60 < 2 ? 0.3 : 1;
|
||||
|
||||
return (
|
||||
<AbsoluteFill
|
||||
style={{
|
||||
backgroundColor: "#0a0a0a",
|
||||
opacity: fadeIn * flicker,
|
||||
}}
|
||||
>
|
||||
<ScanLines opacity={0.15} />
|
||||
<LetterBox />
|
||||
|
||||
{/* Dramatic spotlight */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
width: 800,
|
||||
height: 800,
|
||||
transform: "translate(-50%, -50%)",
|
||||
background:
|
||||
"radial-gradient(circle, rgba(255,255,255,0.05) 0%, transparent 70%)",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Main text */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
<GlitchText
|
||||
style={{
|
||||
fontSize: 72,
|
||||
fontWeight: 300,
|
||||
color: "white",
|
||||
fontFamily: "system-ui, -apple-system, sans-serif",
|
||||
letterSpacing: 8,
|
||||
textTransform: "uppercase",
|
||||
}}
|
||||
>
|
||||
{displayText}
|
||||
</GlitchText>
|
||||
|
||||
{/* Blinking cursor */}
|
||||
{typewriterLength < fullText.length && (
|
||||
<span
|
||||
style={{
|
||||
opacity: frame % 30 < 15 ? 1 : 0,
|
||||
color: "#ef4444",
|
||||
fontSize: 72,
|
||||
fontWeight: 300,
|
||||
}}
|
||||
>
|
||||
_
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Bottom text */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: 180,
|
||||
left: 0,
|
||||
right: 0,
|
||||
textAlign: "center",
|
||||
opacity: interpolate(frame, [fps * 3, fps * 4], [0, 1], {
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 24,
|
||||
color: "#ef4444",
|
||||
fontFamily: "monospace",
|
||||
letterSpacing: 4,
|
||||
}}
|
||||
>
|
||||
YOUR EMOTIONS
|
||||
</div>
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
|
||||
// Scene 2: The Crew - Mood emojis as heist team
|
||||
const CrewScene: React.FC = () => {
|
||||
const frame = useCurrentFrame();
|
||||
const { fps } = useVideoConfig();
|
||||
|
||||
const crew = [
|
||||
{ emoji: "😊", name: "THE OPTIMIST", color: "#10b981", role: "INFILTRATION" },
|
||||
{ emoji: "😤", name: "THE MUSCLE", color: "#ef4444", role: "FIREPOWER" },
|
||||
{ emoji: "🤔", name: "THE BRAINS", color: "#3b82f6", role: "STRATEGY" },
|
||||
{ emoji: "😌", name: "THE COOL", color: "#8b5cf6", role: "EXTRACTION" },
|
||||
];
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ backgroundColor: "#0a0a0a" }}>
|
||||
<ScanLines opacity={0.1} />
|
||||
<LetterBox />
|
||||
|
||||
{/* Title */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 180,
|
||||
left: 0,
|
||||
right: 0,
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 32,
|
||||
color: "#fbbf24",
|
||||
fontFamily: "monospace",
|
||||
letterSpacing: 8,
|
||||
opacity: interpolate(frame, [0, fps * 0.5], [0, 1]),
|
||||
}}
|
||||
>
|
||||
ASSEMBLING THE CREW
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Crew grid */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
display: "grid",
|
||||
gridTemplateColumns: "repeat(2, 1fr)",
|
||||
gap: 60,
|
||||
}}
|
||||
>
|
||||
{crew.map((member, i) => {
|
||||
const delay = i * 8;
|
||||
const memberProgress = spring({
|
||||
frame: frame - delay,
|
||||
fps,
|
||||
config: { damping: 12, stiffness: 100 },
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
key={member.name}
|
||||
style={{
|
||||
textAlign: "center",
|
||||
opacity: interpolate(memberProgress, [0, 1], [0, 1]),
|
||||
transform: `translateY(${interpolate(memberProgress, [0, 1], [50, 0])}px)`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 100,
|
||||
marginBottom: 15,
|
||||
filter: `drop-shadow(0 0 20px ${member.color})`,
|
||||
}}
|
||||
>
|
||||
{member.emoji}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 20,
|
||||
color: member.color,
|
||||
fontFamily: "monospace",
|
||||
fontWeight: 700,
|
||||
letterSpacing: 2,
|
||||
}}
|
||||
>
|
||||
{member.name}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 14,
|
||||
color: "#666",
|
||||
fontFamily: "monospace",
|
||||
marginTop: 5,
|
||||
}}
|
||||
>
|
||||
{member.role}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
|
||||
// Scene 3: The Plan - Blueprint style
|
||||
const PlanScene: React.FC = () => {
|
||||
const frame = useCurrentFrame();
|
||||
const { fps, width, height } = useVideoConfig();
|
||||
|
||||
// Grid lines drawing animation
|
||||
const gridProgress = interpolate(frame, [0, fps * 2], [0, 1], {
|
||||
extrapolateRight: "clamp",
|
||||
});
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ backgroundColor: "#0a1628" }}>
|
||||
<ScanLines opacity={0.05} />
|
||||
<LetterBox />
|
||||
|
||||
{/* Blueprint grid */}
|
||||
<svg
|
||||
style={{ position: "absolute", top: 0, left: 0, width: "100%", height: "100%" }}
|
||||
>
|
||||
{/* Vertical lines */}
|
||||
{[...Array(20)].map((_, i) => (
|
||||
<line
|
||||
key={`v-${i}`}
|
||||
x1={(i * width) / 20}
|
||||
y1={0}
|
||||
x2={(i * width) / 20}
|
||||
y2={height * gridProgress}
|
||||
stroke="#1e40af"
|
||||
strokeWidth={0.5}
|
||||
opacity={0.3}
|
||||
/>
|
||||
))}
|
||||
{/* Horizontal lines */}
|
||||
{[...Array(30)].map((_, i) => (
|
||||
<line
|
||||
key={`h-${i}`}
|
||||
x1={0}
|
||||
y1={(i * height) / 30}
|
||||
x2={width * gridProgress}
|
||||
y2={(i * height) / 30}
|
||||
stroke="#1e40af"
|
||||
strokeWidth={0.5}
|
||||
opacity={0.3}
|
||||
/>
|
||||
))}
|
||||
</svg>
|
||||
|
||||
{/* Phone blueprint */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
opacity: interpolate(frame, [fps, fps * 2], [0, 1], {
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: 300,
|
||||
height: 600,
|
||||
border: "2px solid #3b82f6",
|
||||
borderRadius: 40,
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
{/* Target markers */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "30%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
width: 100,
|
||||
height: 100,
|
||||
border: "2px dashed #ef4444",
|
||||
borderRadius: "50%",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
fontSize: 14,
|
||||
color: "#ef4444",
|
||||
fontFamily: "monospace",
|
||||
}}
|
||||
>
|
||||
TARGET
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Entry point */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: 80,
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
fontSize: 12,
|
||||
color: "#10b981",
|
||||
fontFamily: "monospace",
|
||||
}}
|
||||
>
|
||||
ENTRY POINT
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Title */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 180,
|
||||
left: 0,
|
||||
right: 0,
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 32,
|
||||
color: "#3b82f6",
|
||||
fontFamily: "monospace",
|
||||
letterSpacing: 8,
|
||||
}}
|
||||
>
|
||||
THE PLAN
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Steps */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: 200,
|
||||
left: 60,
|
||||
right: 60,
|
||||
display: "flex",
|
||||
justifyContent: "space-around",
|
||||
}}
|
||||
>
|
||||
{["DOWNLOAD", "TAP MOOD", "REPEAT"].map((step, i) => (
|
||||
<div
|
||||
key={step}
|
||||
style={{
|
||||
opacity: interpolate(
|
||||
frame,
|
||||
[fps * 2 + i * 10, fps * 2.5 + i * 10],
|
||||
[0, 1],
|
||||
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
|
||||
),
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 48,
|
||||
color: "#fbbf24",
|
||||
fontFamily: "monospace",
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
{i + 1}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: "#94a3b8",
|
||||
fontFamily: "monospace",
|
||||
}}
|
||||
>
|
||||
{step}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
|
||||
// Scene 4: The Execution - Dramatic mood selection
|
||||
const ExecutionScene: React.FC = () => {
|
||||
const frame = useCurrentFrame();
|
||||
const { fps } = useVideoConfig();
|
||||
|
||||
const moods = ["😢", "😕", "😐", "🙂", "😊"];
|
||||
const selectedIndex = 4; // Great mood
|
||||
|
||||
// Dramatic slow reveal
|
||||
const revealProgress = interpolate(frame, [0, fps * 2], [0, 1], {
|
||||
extrapolateRight: "clamp",
|
||||
easing: Easing.out(Easing.cubic),
|
||||
});
|
||||
|
||||
// Finger approaching
|
||||
const fingerProgress = interpolate(frame, [fps * 2, fps * 3], [0, 1], {
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
});
|
||||
|
||||
// Selection flash
|
||||
const selectFlash = frame > fps * 3 && frame < fps * 3.5;
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ backgroundColor: "#0a0a0a" }}>
|
||||
<ScanLines opacity={0.1} />
|
||||
<LetterBox />
|
||||
|
||||
{/* Dramatic lighting */}
|
||||
{selectFlash && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: "rgba(16, 185, 129, 0.3)",
|
||||
zIndex: 10,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Mood buttons */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
display: "flex",
|
||||
gap: 30,
|
||||
}}
|
||||
>
|
||||
{moods.map((mood, i) => {
|
||||
const isSelected = i === selectedIndex && frame > fps * 3;
|
||||
const buttonProgress = interpolate(
|
||||
revealProgress,
|
||||
[i * 0.15, i * 0.15 + 0.3],
|
||||
[0, 1],
|
||||
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
style={{
|
||||
width: 120,
|
||||
height: 120,
|
||||
borderRadius: 30,
|
||||
backgroundColor: isSelected ? "#10b981" : "rgba(255,255,255,0.1)",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
fontSize: 60,
|
||||
opacity: buttonProgress,
|
||||
transform: `scale(${isSelected ? 1.2 : 1}) translateY(${interpolate(buttonProgress, [0, 1], [50, 0])}px)`,
|
||||
boxShadow: isSelected ? "0 0 60px #10b981" : "none",
|
||||
transition: "all 0.3s",
|
||||
}}
|
||||
>
|
||||
{mood}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Approaching finger/cursor */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "60%",
|
||||
left: `${50 + 20 - fingerProgress * 8}%`,
|
||||
fontSize: 80,
|
||||
transform: `translateX(-50%) rotate(-30deg)`,
|
||||
opacity: fingerProgress < 1 ? fingerProgress : 0,
|
||||
}}
|
||||
>
|
||||
👆
|
||||
</div>
|
||||
|
||||
{/* "ACQUIRED" text */}
|
||||
{frame > fps * 3.2 && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
bottom: 250,
|
||||
left: 0,
|
||||
right: 0,
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
<GlitchText
|
||||
style={{
|
||||
fontSize: 48,
|
||||
color: "#10b981",
|
||||
fontFamily: "monospace",
|
||||
letterSpacing: 16,
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
MOOD ACQUIRED
|
||||
</GlitchText>
|
||||
</div>
|
||||
)}
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
|
||||
// Scene 5: The Getaway - Success celebration
|
||||
const GetawayScene: React.FC = () => {
|
||||
const frame = useCurrentFrame();
|
||||
const { fps } = useVideoConfig();
|
||||
|
||||
const logoProgress = spring({
|
||||
frame,
|
||||
fps,
|
||||
config: { damping: 10, stiffness: 80 },
|
||||
});
|
||||
|
||||
// Vault door opening effect
|
||||
const vaultOpen = interpolate(frame, [0, fps], [0, 1], {
|
||||
extrapolateRight: "clamp",
|
||||
easing: Easing.out(Easing.cubic),
|
||||
});
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ backgroundColor: "#0a0a0a" }}>
|
||||
<ScanLines opacity={0.05} />
|
||||
<LetterBox />
|
||||
|
||||
{/* Vault doors */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: "50%",
|
||||
height: "100%",
|
||||
backgroundColor: "#1a1a1a",
|
||||
transform: `translateX(${-vaultOpen * 100}%)`,
|
||||
borderRight: "4px solid #333",
|
||||
zIndex: 20,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
right: 0,
|
||||
width: "50%",
|
||||
height: "100%",
|
||||
backgroundColor: "#1a1a1a",
|
||||
transform: `translateX(${vaultOpen * 100}%)`,
|
||||
borderLeft: "4px solid #333",
|
||||
zIndex: 20,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Bright light behind vault */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
width: 600,
|
||||
height: 600,
|
||||
background: `radial-gradient(circle, rgba(251,191,36,${vaultOpen * 0.5}) 0%, transparent 70%)`,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* App icon revealed */}
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: `translate(-50%, -50%) scale(${interpolate(logoProgress, [0, 1], [0.5, 1])})`,
|
||||
textAlign: "center",
|
||||
opacity: vaultOpen,
|
||||
}}
|
||||
>
|
||||
<Img
|
||||
src={staticFile("app-icon.png")}
|
||||
style={{
|
||||
width: 200,
|
||||
height: 200,
|
||||
borderRadius: 200 * 0.22,
|
||||
marginBottom: 40,
|
||||
filter: `drop-shadow(0 0 60px rgba(251,191,36,0.8))`,
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
fontSize: 80,
|
||||
fontWeight: 800,
|
||||
color: "white",
|
||||
fontFamily: "system-ui, -apple-system, sans-serif",
|
||||
textShadow: "0 0 40px rgba(255,255,255,0.5)",
|
||||
}}
|
||||
>
|
||||
Feels
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
fontSize: 28,
|
||||
color: "#fbbf24",
|
||||
fontFamily: "monospace",
|
||||
marginTop: 20,
|
||||
letterSpacing: 4,
|
||||
opacity: interpolate(frame, [fps * 2, fps * 2.5], [0, 1], {
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
}),
|
||||
}}
|
||||
>
|
||||
TAKE BACK YOUR EMOTIONS
|
||||
</div>
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
|
||||
// Main composition - 25 seconds total
|
||||
export const ConceptHMoodHeist: React.FC = () => {
|
||||
const { fps } = useVideoConfig();
|
||||
|
||||
return (
|
||||
<AbsoluteFill>
|
||||
<Sequence from={0} durationInFrames={Math.round(5 * fps)}>
|
||||
<SetupScene />
|
||||
</Sequence>
|
||||
|
||||
<Sequence from={Math.round(5 * fps)} durationInFrames={Math.round(5 * fps)}>
|
||||
<CrewScene />
|
||||
</Sequence>
|
||||
|
||||
<Sequence from={Math.round(10 * fps)} durationInFrames={Math.round(5 * fps)}>
|
||||
<PlanScene />
|
||||
</Sequence>
|
||||
|
||||
<Sequence from={Math.round(15 * fps)} durationInFrames={Math.round(5 * fps)}>
|
||||
<ExecutionScene />
|
||||
</Sequence>
|
||||
|
||||
<Sequence from={Math.round(20 * fps)} durationInFrames={Math.round(5 * fps)}>
|
||||
<GetawayScene />
|
||||
</Sequence>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user