# Promo / Sale Ad Template

Urgency-driven format: Discount → Countdown → CTA

## Structure (10 seconds)

| Scene | Frames | Duration | Content |
|-------|--------|----------|---------|
| Splash | 0-60 | 2s | "SALE" text burst |
| Discount | 60-180 | 4s | Percentage off + original vs sale price |
| Urgency | 180-240 | 2s | Countdown or "Limited Time" |
| CTA | 240-300 | 2s | Shop now button |

## Implementation

```tsx
import {AbsoluteFill, Sequence, interpolate, useCurrentFrame, spring, useVideoConfig} from 'remotion';

interface PromoSaleProps {
  discountPercent: number;
  originalPrice: string;
  salePrice: string;
  urgencyText: string;
  ctaText: string;
  brandColor: string;
  accentColor: string;
}

export const PromoSale: React.FC<PromoSaleProps> = ({
  discountPercent,
  originalPrice,
  salePrice,
  urgencyText,
  ctaText,
  brandColor,
  accentColor,
}) => {
  return (
    <AbsoluteFill style={{backgroundColor: brandColor}}>
      <Sequence from={0} durationInFrames={60}>
        <SplashScene discountPercent={discountPercent} accentColor={accentColor} />
      </Sequence>

      <Sequence from={60} durationInFrames={120}>
        <DiscountScene 
          originalPrice={originalPrice}
          salePrice={salePrice}
          accentColor={accentColor}
        />
      </Sequence>

      <Sequence from={180} durationInFrames={60}>
        <UrgencyScene urgencyText={urgencyText} />
      </Sequence>

      <Sequence from={240} durationInFrames={60}>
        <CTAScene ctaText={ctaText} accentColor={accentColor} />
      </Sequence>
    </AbsoluteFill>
  );
};

const SplashScene: React.FC<{discountPercent: number; accentColor: string}> = ({
  discountPercent,
  accentColor,
}) => {
  const frame = useCurrentFrame();
  const {fps} = useVideoConfig();
  
  // Spring animation for bouncy entrance
  const scale = spring({
    frame,
    fps,
    config: {damping: 10, stiffness: 100},
  });
  
  const rotation = interpolate(frame, [0, 30], [-10, 0], {extrapolateRight: 'clamp'});

  return (
    <AbsoluteFill style={{
      justifyContent: 'center',
      alignItems: 'center',
    }}>
      <div style={{
        transform: `scale(${scale}) rotate(${rotation}deg)`,
        textAlign: 'center',
      }}>
        <div style={{
          fontSize: 180,
          fontWeight: 900,
          color: 'white',
          textShadow: '0 10px 30px rgba(0,0,0,0.3)',
        }}>
          {discountPercent}%
        </div>
        <div style={{
          fontSize: 80,
          fontWeight: 800,
          color: accentColor,
          marginTop: -20,
        }}>
          OFF
        </div>
      </div>
    </AbsoluteFill>
  );
};

const DiscountScene: React.FC<{
  originalPrice: string;
  salePrice: string;
  accentColor: string;
}> = ({originalPrice, salePrice, accentColor}) => {
  const frame = useCurrentFrame();
  const opacity = interpolate(frame, [0, 15], [0, 1], {extrapolateRight: 'clamp'});
  
  // Strikethrough animation
  const strikeWidth = interpolate(frame, [20, 40], [0, 100], {extrapolateRight: 'clamp'});

  return (
    <AbsoluteFill style={{
      justifyContent: 'center',
      alignItems: 'center',
      opacity,
    }}>
      <div style={{textAlign: 'center'}}>
        {/* Original price with strikethrough */}
        <div style={{
          position: 'relative',
          display: 'inline-block',
          marginBottom: 30,
        }}>
          <span style={{
            fontSize: 60,
            color: 'rgba(255,255,255,0.6)',
          }}>
            {originalPrice}
          </span>
          <div style={{
            position: 'absolute',
            top: '50%',
            left: 0,
            height: 4,
            width: `${strikeWidth}%`,
            backgroundColor: accentColor,
          }} />
        </div>
        
        {/* Sale price */}
        <div style={{
          fontSize: 120,
          fontWeight: 900,
          color: 'white',
        }}>
          {salePrice}
        </div>
      </div>
    </AbsoluteFill>
  );
};

const UrgencyScene: React.FC<{urgencyText: string}> = ({urgencyText}) => {
  const frame = useCurrentFrame();
  
  // Pulsing effect
  const scale = interpolate(
    frame % 15,
    [0, 7, 15],
    [1, 1.05, 1],
  );

  return (
    <AbsoluteFill style={{
      justifyContent: 'center',
      alignItems: 'center',
    }}>
      <div style={{
        transform: `scale(${scale})`,
        fontSize: 48,
        fontWeight: 700,
        color: 'white',
        padding: '20px 50px',
        backgroundColor: 'rgba(0,0,0,0.3)',
        borderRadius: 10,
        textTransform: 'uppercase',
        letterSpacing: 4,
      }}>
        ⏰ {urgencyText}
      </div>
    </AbsoluteFill>
  );
};

const CTAScene: React.FC<{ctaText: string; accentColor: string}> = ({ctaText, accentColor}) => {
  const frame = useCurrentFrame();
  const {fps} = useVideoConfig();
  
  const scale = spring({
    frame,
    fps,
    config: {damping: 12, stiffness: 150},
  });

  return (
    <AbsoluteFill style={{
      justifyContent: 'center',
      alignItems: 'center',
    }}>
      <div style={{
        transform: `scale(${scale})`,
        fontSize: 52,
        fontWeight: 700,
        color: 'white',
        padding: '30px 80px',
        backgroundColor: accentColor,
        borderRadius: 50,
        boxShadow: '0 10px 40px rgba(0,0,0,0.3)',
      }}>
        {ctaText} →
      </div>
    </AbsoluteFill>
  );
};
```

## Composition Registration

```tsx
<Composition
  id="PromoSale"
  component={PromoSale}
  durationInFrames={300}
  fps={30}
  width={1080}
  height={1920}
  defaultProps={{
    discountPercent: 50,
    originalPrice: '₱1,999',
    salePrice: '₱999',
    urgencyText: 'Ends Tonight!',
    ctaText: 'Shop Now',
    brandColor: '#dc2626',
    accentColor: '#fbbf24',
  }}
/>
```

## Color Schemes for Sales

| Mood | Brand Color | Accent Color |
|------|------------|--------------|
| Urgent/Hot | `#dc2626` (red) | `#fbbf24` (gold) |
| Premium | `#1e1e1e` (black) | `#f59e0b` (amber) |
| Fresh | `#059669` (emerald) | `#fef3c7` (cream) |
| Tech | `#7c3aed` (violet) | `#22d3ee` (cyan) |
