import { AbsoluteFill, Img, interpolate, spring, useCurrentFrame, useVideoConfig, staticFile, } from "remotion"; export interface AdColors { primary?: string; accent?: string; dark?: string; light?: string; white?: string; red?: string; } export interface HoneyDueAdProps { platform: "instagram" | "tiktok"; hookText: string; bodyText: string; ctaText: string; proofText: string; screenshotSrc: string; colors?: AdColors; appName?: string; } const DEFAULT_COLORS = { primary: "#0079FF", accent: "#FF9400", dark: "#1a1a2e", light: "#f8f6f2", white: "#ffffff", red: "#FF3B30", }; export const HoneyDueAd: React.FC = ({ platform, hookText, bodyText, ctaText, proofText, screenshotSrc, colors, appName = "honeyDue", }) => { const COLORS = { ...DEFAULT_COLORS, ...colors }; const frame = useCurrentFrame(); const { fps, durationInFrames, width, height } = useVideoConfig(); const isPolished = platform === "instagram"; const bg = isPolished ? COLORS.dark : "#0d0d0d"; // Scene boundaries const hookEnd = Math.floor(durationInFrames * 0.22); const phoneStart = hookEnd; const phoneEnd = Math.floor(durationInFrames * 0.6); const proofStart = phoneEnd; const proofEnd = Math.floor(durationInFrames * 0.78); const ctaStart = proofEnd; // === HOOK SCENE === const hookOpacity = interpolate( frame, [0, 10, hookEnd - 8, hookEnd], [0, 1, 1, 0], { extrapolateRight: "clamp" } ); const hookY = interpolate(frame, [0, 15], [40, 0], { extrapolateRight: "clamp", }); // === PHONE SCENE === const phoneScale = spring({ frame: Math.max(0, frame - phoneStart), fps, config: { damping: 14, stiffness: 80 }, }); const phoneOpacity = interpolate( frame, [phoneStart, phoneStart + 10, phoneEnd - 8, phoneEnd], [0, 1, 1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" } ); const bodyTextOpacity = interpolate( frame, [phoneStart + 20, phoneStart + 35], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" } ); // === PROOF SCENE === const proofOpacity = interpolate( frame, [proofStart, proofStart + 12, proofEnd - 8, proofEnd], [0, 1, 1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" } ); const proofScale = spring({ frame: Math.max(0, frame - proofStart), fps, config: { damping: 12 }, }); // === CTA SCENE === const ctaOpacity = interpolate(frame, [ctaStart, ctaStart + 12], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp", }); const ctaScale = spring({ frame: Math.max(0, frame - ctaStart), fps, config: { damping: 10, stiffness: 100 }, }); // Pulse the CTA button const ctaPulse = frame > ctaStart + 20 ? 1 + 0.03 * Math.sin((frame - ctaStart - 20) * 0.15) : 1; const phoneWidth = width * 0.55; const phoneHeight = phoneWidth * 2.05; return ( {/* Subtle gradient overlay */}
{/* === HOOK === */}
{hookText}
{/* === PHONE + BODY TEXT === */}
{/* Body text above phone */}
{bodyText}
{/* Phone mockup — real phone.png frame over screenshot */}
{/* Screenshot behind the frame — clipped to screen area */}
{/* Phone frame on top */}
{/* === PROOF === */}
{proofText}
Join thousands of homeowners
{/* === CTA === */}
{/* Brand name header */}
{appName}
{/* Icon — 50% of canvas width, centered */} {/* CTA button */}
{ctaText}
); };