Party Invite Video (Remotion)
An energetic 4-second portrait party invitation built with Remotion in 1080×1920 9:16 format. A spring-powered YOU'RE INVITED headline explodes in with scale overshoot and a shimmer sweep, followed by a neon-bordered event name badge. Date, time, and location cards stagger up from below with individual spring entrances and glow-icon badges in electric blue, hot pink, and lime green. A pulsing RSVP deadline pill with a repeating ring animation and continuous shimmer loop closes the invite over a dark canvas layered with drifting confetti and twinkling SVG sparkle shapes.
Preview
Code
import React from "react";
import {
AbsoluteFill,
Composition,
Easing,
Sequence,
interpolate,
spring,
useCurrentFrame,
useVideoConfig,
} from "remotion";
// ── Config ────────────────────────────────────────────────────────────────────
const EVENT_NAME = "NEON DREAMS";
const EVENT_SUBTITLE = "The Rooftop Rave";
const EVENT_DATE = "SAT, JULY 19";
const EVENT_TIME = "10 PM – 4 AM";
const EVENT_PLACE = "SkyDeck, Level 42";
const EVENT_ADDRESS = "42 Vertigo Blvd, NYC";
const RSVP_DEADLINE = "RSVP by July 14";
const DRESS_CODE = "Neon / Glow-in-Dark";
const COLOR_BLUE = "#00d4ff";
const COLOR_PINK = "#ff2d87";
const COLOR_LIME = "#b8ff00";
const COLOR_PURPLE = "#bf00ff";
const COLOR_ORANGE = "#ff6a00";
const BG_DARK = "#060612";
const DURATION = 120;
// ── Deterministic geometry helpers ───────────────────────────────────────────
// Golden-ratio scramble so particles are spread without Math.random()
function seeded(i: number, salt: number) {
return ((i * 137.508 + salt * 53.29) % 1) * 1;
}
function seededRange(i: number, salt: number, lo: number, hi: number) {
return lo + seeded(i, salt) * (hi - lo);
}
// ── Sparkle/star SVG paths (pre-computed, no Math.random) ─────────────────────
const SPARKLE_DATA = Array.from({ length: 24 }, (_, i) => {
const x = seededRange(i, 1, 60, 1020);
const y = seededRange(i, 2, 80, 1840);
const size = seededRange(i, 3, 12, 32);
const delay = seededRange(i, 4, 0, 60);
const spin = seededRange(i, 5, 0, 360);
const color = [COLOR_BLUE, COLOR_PINK, COLOR_LIME, COLOR_PURPLE, COLOR_ORANGE][i % 5];
const kind = i % 3; // 0=4-point star, 1=diamond, 2=cross
return { x, y, size, delay, spin, color, kind };
});
// Confetti particles — portrait 1080×1920
const CONFETTI = Array.from({ length: 64 }, (_, i) => ({
x: seededRange(i, 10, 0, 1080),
y: seededRange(i, 11, -200, 1920),
size: seededRange(i, 12, 5, 14),
speed: seededRange(i, 13, 0.5, 2.2),
sway: seededRange(i, 14, 0.02, 0.08),
phase: seededRange(i, 15, 0, Math.PI * 2),
spinRate: seededRange(i, 16, 0.03, 0.12),
color: [COLOR_PINK, COLOR_BLUE, COLOR_LIME, COLOR_PURPLE, COLOR_ORANGE, "#ffffff"][i % 6],
shape: i % 4 === 0 ? "circle" : i % 4 === 1 ? "rect" : i % 4 === 2 ? "diamond" : "pill",
}));
// ── SVG Sparkle shape ─────────────────────────────────────────────────────────
const SparkleShape: React.FC<{
size: number;
color: string;
kind: number;
}> = ({ size, color, kind }) => {
const r = size / 2;
if (kind === 0) {
// 4-point star
const pts = Array.from({ length: 4 }, (_, i) => {
const outerAngle = (i * Math.PI) / 2 - Math.PI / 4;
const innerAngle = outerAngle + Math.PI / 4;
const ox = Math.cos(outerAngle) * r;
const oy = Math.sin(outerAngle) * r;
const ix = Math.cos(innerAngle) * r * 0.38;
const iy = Math.sin(innerAngle) * r * 0.38;
return `${ox + r},${oy + r} ${ix + r},${iy + r}`;
}).join(" ");
return (
<svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
<polygon points={pts} fill={color} opacity={0.9} />
</svg>
);
}
if (kind === 1) {
// Diamond
return (
<svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
<polygon
points={`${r},0 ${size},${r} ${r},${size} 0,${r}`}
fill={color}
opacity={0.85}
/>
</svg>
);
}
// Cross / plus
const t = size * 0.28;
return (
<svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
<rect x={r - t / 2} y={0} width={t} height={size} fill={color} opacity={0.85} rx={t / 2} />
<rect x={0} y={r - t / 2} width={size} height={t} fill={color} opacity={0.85} rx={t / 2} />
</svg>
);
};
// ── Background — deep dark with neon radial glows ────────────────────────────
const Background: React.FC<{ frame: number }> = ({ frame }) => {
const fadeIn = interpolate(frame, [0, 24], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.out(Easing.cubic),
});
// Slow pulse on glows
const pulse = Math.sin(frame * 0.05);
const pinkGlow = interpolate(pulse, [-1, 1], [0.08, 0.16], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const blueGlow = interpolate(pulse, [-1, 1], [0.06, 0.13], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return (
<>
{/* Base */}
<div style={{ position: "absolute", inset: 0, backgroundColor: BG_DARK }} />
{/* Neon pink glow — top center */}
<div
style={{
position: "absolute",
top: -200,
left: "50%",
width: 900,
height: 900,
borderRadius: "50%",
background: `radial-gradient(circle, ${COLOR_PINK} 0%, transparent 65%)`,
transform: "translateX(-50%)",
opacity: pinkGlow * fadeIn,
}}
/>
{/* Electric blue glow — lower left */}
<div
style={{
position: "absolute",
bottom: 200,
left: -200,
width: 800,
height: 800,
borderRadius: "50%",
background: `radial-gradient(circle, ${COLOR_BLUE} 0%, transparent 65%)`,
opacity: blueGlow * fadeIn,
}}
/>
{/* Lime accent glow — lower right */}
<div
style={{
position: "absolute",
bottom: 100,
right: -100,
width: 600,
height: 600,
borderRadius: "50%",
background: `radial-gradient(circle, ${COLOR_LIME} 0%, transparent 65%)`,
opacity: (blueGlow * 0.55) * fadeIn,
}}
/>
{/* Subtle scan-line grid */}
<div
style={{
position: "absolute",
inset: 0,
backgroundImage:
"repeating-linear-gradient(0deg, rgba(255,255,255,0.012) 0px, rgba(255,255,255,0.012) 1px, transparent 1px, transparent 48px)",
opacity: fadeIn,
}}
/>
</>
);
};
// ── Floating sparkles ─────────────────────────────────────────────────────────
const FloatingSparkles: React.FC<{ frame: number }> = ({ frame }) => {
return (
<div style={{ position: "absolute", inset: 0, pointerEvents: "none" }}>
{SPARKLE_DATA.map((sp, i) => {
const f = Math.max(0, frame - sp.delay);
const appear = interpolate(f, [0, 12], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// Twinkle pulse
const twinkle = interpolate(
Math.sin(f * 0.15 + i * 0.7),
[-1, 1],
[0.3, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
const spinAngle = (f * 0.6 + sp.spin) % 360;
const floatY = Math.sin(f * 0.04 + i * 0.5) * 8;
return (
<div
key={i}
style={{
position: "absolute",
left: sp.x,
top: sp.y + floatY,
opacity: appear * twinkle,
transform: `rotate(${spinAngle}deg)`,
filter: `drop-shadow(0 0 ${sp.size * 0.4}px ${sp.color}cc)`,
}}
>
<SparkleShape size={sp.size} color={sp.color} kind={sp.kind} />
</div>
);
})}
</div>
);
};
// ── Confetti burst ────────────────────────────────────────────────────────────
const ConfettiBurst: React.FC<{ frame: number }> = ({ frame }) => {
const globalReveal = interpolate(frame, [6, 22], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return (
<div style={{ position: "absolute", inset: 0, pointerEvents: "none", overflow: "hidden" }}>
{CONFETTI.map((p, i) => {
const localFrame = frame;
const drift = (p.y + localFrame * p.speed) % 2100 - 100;
const swayX = Math.sin(localFrame * p.sway + p.phase) * 28;
const rotate = (localFrame * p.spinRate * 180) % 360;
const opacity =
globalReveal *
interpolate(localFrame, [0, 16], [0, 0.8], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const sStyle: React.CSSProperties =
p.shape === "circle"
? { borderRadius: "50%", width: p.size, height: p.size }
: p.shape === "pill"
? { borderRadius: 99, width: p.size * 2, height: p.size * 0.55 }
: p.shape === "diamond"
? {
width: p.size,
height: p.size,
transform: `rotate(${rotate + 45}deg)`,
borderRadius: 2,
}
: { borderRadius: 2, width: p.size * 1.5, height: p.size * 0.6 };
return (
<div
key={i}
style={{
position: "absolute",
left: p.x + swayX,
top: drift,
backgroundColor: p.color,
opacity,
transform: p.shape !== "diamond" ? `rotate(${rotate}deg)` : undefined,
...sStyle,
}}
/>
);
})}
</div>
);
};
// ── "YOU'RE INVITED" hero title ───────────────────────────────────────────────
const HeroTitle: React.FC<{ frame: number; fps: number }> = ({ frame, fps }) => {
const scale = spring({
frame,
fps,
from: 0,
to: 1,
config: { damping: 8, stiffness: 160, mass: 0.6 },
});
const opacity = interpolate(frame, [0, 8], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// Shimmer sweep
const shimmerX = interpolate(frame, [18, 55], [-300, 1200], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.inOut(Easing.cubic),
});
// Subtle glow pulse after entrance
const glowPulse = interpolate(
Math.sin(frame * 0.1),
[-1, 1],
[30, 55],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
return (
<div
style={{
position: "relative",
opacity,
transform: `scale(${scale})`,
transformOrigin: "center center",
textAlign: "center",
overflow: "hidden",
borderRadius: 8,
paddingLeft: 20,
paddingRight: 20,
}}
>
<span
style={{
fontFamily: "system-ui, -apple-system, sans-serif",
fontWeight: 900,
fontSize: 108,
letterSpacing: -2,
lineHeight: 0.9,
background: `linear-gradient(130deg, ${COLOR_PINK} 0%, #ff80b4 30%, ${COLOR_BLUE} 65%, ${COLOR_LIME} 100%)`,
WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent",
backgroundClip: "text",
display: "block",
filter: `drop-shadow(0 0 ${glowPulse}px ${COLOR_PINK}80) drop-shadow(0 0 ${glowPulse * 0.6}px ${COLOR_BLUE}60)`,
}}
>
YOU'RE
</span>
<span
style={{
fontFamily: "system-ui, -apple-system, sans-serif",
fontWeight: 900,
fontSize: 108,
letterSpacing: -2,
lineHeight: 0.95,
background: `linear-gradient(130deg, ${COLOR_LIME} 0%, ${COLOR_BLUE} 45%, ${COLOR_PINK} 100%)`,
WebkitBackgroundClip: "text",
WebkitTextFillColor: "transparent",
backgroundClip: "text",
display: "block",
filter: `drop-shadow(0 0 ${glowPulse}px ${COLOR_LIME}70) drop-shadow(0 0 ${glowPulse * 0.5}px ${COLOR_BLUE}50)`,
}}
>
INVITED
</span>
{/* Shimmer highlight */}
<div
style={{
position: "absolute",
top: 0,
left: shimmerX,
width: 160,
height: "100%",
background:
"linear-gradient(90deg, transparent, rgba(255,255,255,0.25), transparent)",
transform: "skewX(-8deg)",
pointerEvents: "none",
}}
/>
</div>
);
};
// ── Event name badge ──────────────────────────────────────────────────────────
const EventNameBadge: React.FC<{ frame: number; fps: number }> = ({ frame, fps }) => {
const START = 18;
const f = Math.max(0, frame - START);
const scale = spring({
frame: f,
fps,
from: 0.6,
to: 1,
config: { damping: 12, stiffness: 200, mass: 0.5 },
});
const opacity = interpolate(f, [0, 10], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const glowPulse = interpolate(Math.sin(frame * 0.08), [-1, 1], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return (
<div
style={{
opacity,
transform: `scale(${scale})`,
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: 4,
marginTop: 8,
}}
>
<div
style={{
background: `linear-gradient(135deg, ${COLOR_PINK}22, ${COLOR_PURPLE}22)`,
border: `2px solid ${COLOR_PINK}60`,
borderRadius: 16,
paddingTop: 16,
paddingBottom: 16,
paddingLeft: 40,
paddingRight: 40,
boxShadow: `0 0 ${20 + glowPulse * 20}px ${COLOR_PINK}40, inset 0 1px 0 rgba(255,255,255,0.1)`,
}}
>
<span
style={{
fontFamily: "system-ui, -apple-system, sans-serif",
fontWeight: 900,
fontSize: 64,
letterSpacing: 6,
color: "#ffffff",
textShadow: `0 0 20px ${COLOR_PINK}90, 0 0 40px ${COLOR_PINK}50`,
display: "block",
textAlign: "center",
}}
>
{EVENT_NAME}
</span>
<span
style={{
fontFamily: "system-ui, -apple-system, sans-serif",
fontWeight: 400,
fontSize: 28,
color: `${COLOR_BLUE}cc`,
letterSpacing: 4,
display: "block",
textAlign: "center",
marginTop: 2,
}}
>
{EVENT_SUBTITLE}
</span>
</div>
</div>
);
};
// ── Detail row (icon + label + value) ────────────────────────────────────────
const DetailRow: React.FC<{
icon: React.ReactNode;
label: string;
value: string;
subvalue?: string;
accent: string;
frame: number;
fps: number;
startFrame: number;
}> = ({ icon, label, value, subvalue, accent, frame, fps, startFrame }) => {
const f = Math.max(0, frame - startFrame);
const y = spring({
frame: f,
fps,
from: 40,
to: 0,
config: { damping: 13, stiffness: 160, mass: 0.55 },
});
const opacity = interpolate(f, [0, 12], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return (
<div
style={{
opacity,
transform: `translateY(${y}px)`,
display: "flex",
alignItems: "center",
gap: 20,
width: "100%",
padding: "18px 0",
borderBottom: `1px solid rgba(255,255,255,0.07)`,
}}
>
{/* Icon circle */}
<div
style={{
width: 64,
height: 64,
borderRadius: 18,
background: `${accent}18`,
border: `1.5px solid ${accent}50`,
display: "flex",
alignItems: "center",
justifyContent: "center",
flexShrink: 0,
boxShadow: `0 0 16px ${accent}25`,
}}
>
{icon}
</div>
{/* Text */}
<div style={{ display: "flex", flexDirection: "column", gap: 2 }}>
<span
style={{
fontFamily: "system-ui, -apple-system, sans-serif",
fontWeight: 600,
fontSize: 20,
color: `${accent}cc`,
letterSpacing: 2,
textTransform: "uppercase" as const,
}}
>
{label}
</span>
<span
style={{
fontFamily: "system-ui, -apple-system, sans-serif",
fontWeight: 800,
fontSize: 34,
color: "#ffffff",
letterSpacing: -0.5,
textShadow: `0 0 12px ${accent}40`,
}}
>
{value}
</span>
{subvalue && (
<span
style={{
fontFamily: "system-ui, -apple-system, sans-serif",
fontWeight: 400,
fontSize: 22,
color: "rgba(255,255,255,0.5)",
}}
>
{subvalue}
</span>
)}
</div>
</div>
);
};
// ── Calendar SVG icon ─────────────────────────────────────────────────────────
const CalendarIcon: React.FC<{ color: string }> = ({ color }) => (
<svg width="32" height="32" viewBox="0 0 32 32" fill="none">
<rect x="2" y="6" width="28" height="24" rx="4" stroke={color} strokeWidth="2" />
<line x1="2" y1="13" x2="30" y2="13" stroke={color} strokeWidth="1.5" />
<line x1="10" y1="2" x2="10" y2="10" stroke={color} strokeWidth="2" strokeLinecap="round" />
<line x1="22" y1="2" x2="22" y2="10" stroke={color} strokeWidth="2" strokeLinecap="round" />
<rect x="7" y="18" width="5" height="5" rx="1" fill={color} opacity="0.8" />
<rect x="14" y="18" width="5" height="5" rx="1" fill={color} opacity="0.8" />
</svg>
);
// ── Clock SVG icon ────────────────────────────────────────────────────────────
const ClockIcon: React.FC<{ color: string }> = ({ color }) => (
<svg width="32" height="32" viewBox="0 0 32 32" fill="none">
<circle cx="16" cy="16" r="13" stroke={color} strokeWidth="2" />
<line x1="16" y1="8" x2="16" y2="16" stroke={color} strokeWidth="2.2" strokeLinecap="round" />
<line x1="16" y1="16" x2="22" y2="20" stroke={color} strokeWidth="2.2" strokeLinecap="round" />
<circle cx="16" cy="16" r="2" fill={color} />
</svg>
);
// ── Map pin SVG icon ──────────────────────────────────────────────────────────
const PinIcon: React.FC<{ color: string }> = ({ color }) => (
<svg width="32" height="32" viewBox="0 0 32 32" fill="none">
<path
d="M16 2C11.03 2 7 6.03 7 11c0 7.5 9 19 9 19s9-11.5 9-19c0-4.97-4.03-9-9-9z"
stroke={color}
strokeWidth="2"
/>
<circle cx="16" cy="11" r="3.5" fill={color} opacity="0.85" />
</svg>
);
// ── RSVP pulsing deadline pill ────────────────────────────────────────────────
const RsvpBadge: React.FC<{ frame: number; fps: number }> = ({ frame, fps }) => {
const START = 86;
const f = Math.max(0, frame - START);
const scale = spring({
frame: f,
fps,
from: 0.5,
to: 1,
config: { damping: 9, stiffness: 240, mass: 0.45 },
});
const opacity = interpolate(f, [0, 8], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// Pulse glow ring
const ringPhase = Math.max(0, f - 10) % 36;
const ringScale = interpolate(ringPhase, [0, 36], [1, 1.18], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const ringOpacity = interpolate(ringPhase, [0, 12, 36], [0.7, 0.3, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const showRing = f >= 10;
// Shimmer
const shimmerX = interpolate(Math.max(0, f - 14) % 44, [0, 44], [-100, 460], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const showShimmer = f >= 14;
// Breathe
const breathe = interpolate(Math.sin(f * 0.13), [-1, 1], [0.98, 1.02], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// Dot blink
const dotOpacity = interpolate(Math.sin(frame * 0.22), [-1, 1], [0.4, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return (
<div
style={{
opacity,
transform: `scale(${scale * breathe})`,
position: "relative",
display: "inline-block",
width: "100%",
}}
>
{/* Pulse ring */}
{showRing && (
<div
style={{
position: "absolute",
inset: -6,
borderRadius: 22,
border: `2.5px solid ${COLOR_LIME}`,
opacity: ringOpacity,
transform: `scale(${ringScale})`,
pointerEvents: "none",
}}
/>
)}
<div
style={{
position: "relative",
background: `linear-gradient(135deg, ${COLOR_LIME}28 0%, ${COLOR_LIME}10 100%)`,
border: `2px solid ${COLOR_LIME}70`,
borderRadius: 18,
padding: "20px 36px",
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: 14,
boxShadow: `0 0 32px ${COLOR_LIME}30, 0 8px 24px rgba(0,0,0,0.5)`,
overflow: "hidden",
}}
>
<div
style={{
width: 12,
height: 12,
borderRadius: "50%",
backgroundColor: COLOR_LIME,
boxShadow: `0 0 10px ${COLOR_LIME}, 0 0 20px ${COLOR_LIME}80`,
opacity: dotOpacity,
flexShrink: 0,
}}
/>
<span
style={{
fontFamily: "system-ui, -apple-system, sans-serif",
fontWeight: 900,
fontSize: 36,
color: COLOR_LIME,
letterSpacing: 2,
textShadow: `0 0 16px ${COLOR_LIME}80`,
position: "relative",
zIndex: 1,
}}
>
{RSVP_DEADLINE}
</span>
{/* Shimmer */}
{showShimmer && (
<div
style={{
position: "absolute",
top: 0,
left: shimmerX,
width: 100,
height: "100%",
background:
"linear-gradient(90deg, transparent, rgba(255,255,255,0.18), transparent)",
transform: "skewX(-10deg)",
pointerEvents: "none",
}}
/>
)}
</div>
</div>
);
};
// ── Dress code tag ────────────────────────────────────────────────────────────
const DressCodeTag: React.FC<{ frame: number; fps: number }> = ({ frame, fps }) => {
const START = 100;
const f = Math.max(0, frame - START);
const y = spring({
frame: f,
fps,
from: 24,
to: 0,
config: { damping: 14, stiffness: 180 },
});
const opacity = interpolate(f, [0, 10], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return (
<div
style={{
opacity,
transform: `translateY(${y}px)`,
display: "flex",
alignItems: "center",
gap: 12,
marginTop: 4,
}}
>
<span
style={{
fontFamily: "system-ui, -apple-system, sans-serif",
fontWeight: 600,
fontSize: 22,
color: `${COLOR_PURPLE}aa`,
letterSpacing: 2,
textTransform: "uppercase" as const,
}}
>
Dress Code:
</span>
<span
style={{
fontFamily: "system-ui, -apple-system, sans-serif",
fontWeight: 800,
fontSize: 22,
color: COLOR_PURPLE,
letterSpacing: 1,
textShadow: `0 0 12px ${COLOR_PURPLE}80`,
}}
>
{DRESS_CODE}
</span>
</div>
);
};
// ── "Party mode" top pill badge ───────────────────────────────────────────────
const PartyBadge: React.FC<{ frame: number; fps: number }> = ({ frame, fps }) => {
const f = Math.max(0, frame - 4);
const scale = spring({
frame: f,
fps,
from: 0,
to: 1,
config: { damping: 11, stiffness: 240, mass: 0.4 },
});
const opacity = interpolate(f, [0, 8], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// Emoji pop-bounce
const emojiScale = spring({
frame: Math.max(0, f - 6),
fps,
from: 0,
to: 1,
config: { damping: 7, stiffness: 300, mass: 0.3 },
});
return (
<div
style={{
position: "absolute",
top: 80,
left: "50%",
transform: `translateX(-50%) scale(${scale})`,
transformOrigin: "center top",
opacity,
display: "flex",
alignItems: "center",
gap: 10,
background: "rgba(255,255,255,0.06)",
border: "1px solid rgba(255,255,255,0.12)",
borderRadius: 40,
paddingTop: 10,
paddingBottom: 10,
paddingLeft: 24,
paddingRight: 24,
backdropFilter: "blur(8px)",
whiteSpace: "nowrap" as const,
}}
>
<span style={{ fontSize: 28, transform: `scale(${emojiScale})`, display: "inline-block" }}>
🎉
</span>
<span
style={{
fontFamily: "system-ui, -apple-system, sans-serif",
fontWeight: 700,
fontSize: 22,
color: "rgba(255,255,255,0.85)",
letterSpacing: 3,
textTransform: "uppercase" as const,
}}
>
Party Mode ON
</span>
<span style={{ fontSize: 28, transform: `scale(${emojiScale})`, display: "inline-block" }}>
🎊
</span>
</div>
);
};
// ── Divider line ──────────────────────────────────────────────────────────────
const GlowDivider: React.FC<{ frame: number; delay: number; color: string }> = ({
frame,
delay,
color,
}) => {
const f = Math.max(0, frame - delay);
const scaleX = interpolate(f, [0, 22], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.out(Easing.cubic),
});
const opacity = interpolate(f, [0, 12], [0, 0.6], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return (
<div
style={{
height: 1.5,
width: "100%",
background: `linear-gradient(90deg, transparent 0%, ${color}80 30%, ${color} 50%, ${color}80 70%, transparent 100%)`,
transformOrigin: "left center",
transform: `scaleX(${scaleX})`,
opacity,
marginTop: 6,
marginBottom: 6,
boxShadow: `0 0 8px ${color}60`,
}}
/>
);
};
// ── Main composition ──────────────────────────────────────────────────────────
export const RemotionPartyInvite: React.FC = () => {
const frame = useCurrentFrame();
const { fps, durationInFrames } = useVideoConfig();
const globalOpacity = interpolate(
frame,
[durationInFrames - 18, durationInFrames],
[1, 0],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
return (
<AbsoluteFill style={{ opacity: globalOpacity, overflow: "hidden" }}>
<Background frame={frame} />
<ConfettiBurst frame={frame} />
<FloatingSparkles frame={frame} />
{/* Party mode badge */}
<PartyBadge frame={frame} fps={fps} />
{/* Main column layout */}
<div
style={{
position: "absolute",
inset: 0,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
paddingLeft: 48,
paddingRight: 48,
paddingTop: 160,
paddingBottom: 60,
gap: 0,
}}
>
{/* YOU'RE INVITED */}
<HeroTitle frame={frame} fps={fps} />
{/* Event name badge */}
<EventNameBadge frame={frame} fps={fps} />
<GlowDivider frame={frame} delay={28} color={COLOR_PINK} />
{/* Detail rows */}
<div style={{ width: "100%", marginTop: 4 }}>
<DetailRow
icon={<CalendarIcon color={COLOR_BLUE} />}
label="Date"
value={EVENT_DATE}
accent={COLOR_BLUE}
frame={frame}
fps={fps}
startFrame={38}
/>
<DetailRow
icon={<ClockIcon color={COLOR_PINK} />}
label="Time"
value={EVENT_TIME}
accent={COLOR_PINK}
frame={frame}
fps={fps}
startFrame={52}
/>
<DetailRow
icon={<PinIcon color={COLOR_LIME} />}
label="Location"
value={EVENT_PLACE}
subvalue={EVENT_ADDRESS}
accent={COLOR_LIME}
frame={frame}
fps={fps}
startFrame={66}
/>
</div>
<GlowDivider frame={frame} delay={78} color={COLOR_LIME} />
{/* RSVP badge */}
<div style={{ width: "100%", marginTop: 12 }}>
<RsvpBadge frame={frame} fps={fps} />
</div>
{/* Dress code */}
<DressCodeTag frame={frame} fps={fps} />
</div>
</AbsoluteFill>
);
};
// ── Remotion Root ─────────────────────────────────────────────────────────────
export const RemotionRoot: React.FC = () => (
<Composition
id="RemotionPartyInvite"
component={RemotionPartyInvite}
durationInFrames={DURATION}
fps={30}
width={1080}
height={1920}
/>
);Party Invite Video
A high-energy portrait party invitation rendered entirely with Remotion. The composition opens as 64 confetti particles begin drifting down the canvas and 24 SVG sparkle shapes (4-point stars, diamonds, and crosses) twinkle into view, each offset by a golden-ratio delay so no two appear at the same moment. Three layered radial glows in pink, electric blue, and lime green pulse slowly over the near-black background, giving the scene an unmistakable neon-rave atmosphere.
At frame 0 the “YOU’RE INVITED” headline explodes in with a spring scale overshoot, its two lines filled with opposing neon gradients (pink → blue → lime) and accented by a single-shot shimmer sweep. A “NEON DREAMS / The Rooftop Rave” event badge springs in beneath it, bordered by a hot-pink glow that breathes gently throughout the clip. Three detail rows — Date, Time, and Location — stagger up from below with per-row spring entrances, each paired with a custom SVG icon (calendar, clock, map pin) rendered in its own accent color.
The final section delivers an RSVP deadline pill in lime green that springs in with a scale bounce, then emits a continuous repeating ring pulse and a looping shimmer sweep to keep the viewer’s eye anchored on the call-to-action. A dress-code line slides up last before the entire composition fades out over the final 18 frames. All event copy lives in top-level constants — swap EVENT_NAME, EVENT_DATE, EVENT_TIME, EVENT_PLACE, and the color tokens to rebrand the invite in seconds.
Composition specs
| Property | Value |
|---|---|
| Resolution | 1080 × 1920 |
| FPS | 30 |
| Duration | 4 s (120 frames) |
Timeline
| Time | Action |
|---|---|
| 0.0 s (frames 0–15) | Background glows fade in; confetti and sparkles begin appearing; “Party Mode ON” pill springs down from top |
| 0.0 s (frames 0–18) | “YOU’RE INVITED” headline pops in with spring scale overshoot; shimmer sweeps across gradient text |
| 0.6 s (frames 18–28) | Event name badge springs in; horizontal divider line draws left-to-right |
| 1.3 s (frames 38–75) | Date, Time, and Location rows stagger up with spring entrances and colored SVG icon badges |
| 2.9 s (frames 86–110) | RSVP deadline pill bounces in; pulse ring and shimmer loop begin; dress-code tag slides up |
| 3.4 s (frames 102–120) | Global fade-out over final 18 frames |