# Testimonial Ad Template

Social proof format: Quote → Person → CTA

## Structure (15 seconds)

| Scene | Frames | Duration | Content |
|-------|--------|----------|---------|
| Quote | 0-180 | 6s | Customer quote with typing effect |
| Person | 180-330 | 5s | Photo + name + title |
| CTA | 330-450 | 4s | Logo + action |

## Implementation

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

interface TestimonialProps {
  quote: string;
  customerName: string;
  customerTitle: string;
  customerPhotoUrl: string;
  brandColor: string;
  logoUrl: string;
  ctaText: string;
}

export const Testimonial: React.FC<TestimonialProps> = ({
  quote,
  customerName,
  customerTitle,
  customerPhotoUrl,
  brandColor,
  logoUrl,
  ctaText,
}) => {
  return (
    <AbsoluteFill style={{backgroundColor: '#f8f9fa'}}>
      {/* Opening quote marks */}
      <div style={{
        position: 'absolute',
        top: 200,
        left: 60,
        fontSize: 200,
        color: brandColor,
        opacity: 0.2,
        fontFamily: 'Georgia, serif',
      }}>
        "
      </div>

      <Sequence from={0} durationInFrames={180}>
        <QuoteScene quote={quote} brandColor={brandColor} />
      </Sequence>

      <Sequence from={180} durationInFrames={150}>
        <PersonScene 
          customerName={customerName}
          customerTitle={customerTitle}
          customerPhotoUrl={customerPhotoUrl}
          brandColor={brandColor}
        />
      </Sequence>

      <Sequence from={330} durationInFrames={120}>
        <CTAScene logoUrl={logoUrl} ctaText={ctaText} brandColor={brandColor} />
      </Sequence>
    </AbsoluteFill>
  );
};

const QuoteScene: React.FC<{quote: string; brandColor: string}> = ({quote, brandColor}) => {
  const frame = useCurrentFrame();
  
  // Typing effect - reveal characters over time
  const charsToShow = Math.floor(interpolate(frame, [0, 120], [0, quote.length], {
    extrapolateRight: 'clamp',
  }));
  
  const displayedQuote = quote.slice(0, charsToShow);

  return (
    <AbsoluteFill style={{
      justifyContent: 'center',
      alignItems: 'center',
      padding: 80,
    }}>
      <p style={{
        fontSize: 48,
        fontWeight: 500,
        color: '#1a1a1a',
        lineHeight: 1.5,
        textAlign: 'center',
        fontStyle: 'italic',
      }}>
        "{displayedQuote}"
        <span style={{
          opacity: frame % 30 < 15 ? 1 : 0, // Blinking cursor
          color: brandColor,
        }}>|</span>
      </p>
    </AbsoluteFill>
  );
};

const PersonScene: React.FC<{
  customerName: string;
  customerTitle: string;
  customerPhotoUrl: string;
  brandColor: string;
}> = ({customerName, customerTitle, customerPhotoUrl, brandColor}) => {
  const frame = useCurrentFrame();
  const opacity = interpolate(frame, [0, 20], [0, 1], {extrapolateRight: 'clamp'});
  const scale = interpolate(frame, [0, 25], [0.9, 1], {extrapolateRight: 'clamp'});

  return (
    <AbsoluteFill style={{
      justifyContent: 'center',
      alignItems: 'center',
    }}>
      <div style={{
        opacity,
        transform: `scale(${scale})`,
        textAlign: 'center',
      }}>
        <Img 
          src={customerPhotoUrl}
          style={{
            width: 200,
            height: 200,
            borderRadius: 100,
            objectFit: 'cover',
            border: `4px solid ${brandColor}`,
            marginBottom: 30,
          }}
        />
        <div style={{
          fontSize: 42,
          fontWeight: 700,
          color: '#1a1a1a',
          marginBottom: 10,
        }}>
          {customerName}
        </div>
        <div style={{
          fontSize: 28,
          color: '#666',
        }}>
          {customerTitle}
        </div>
      </div>
    </AbsoluteFill>
  );
};

const CTAScene: React.FC<{logoUrl: string; ctaText: string; brandColor: string}> = ({
  logoUrl,
  ctaText,
  brandColor,
}) => {
  const frame = useCurrentFrame();
  const scale = interpolate(frame, [0, 15, 20], [0, 1.1, 1], {extrapolateRight: 'clamp'});

  return (
    <AbsoluteFill style={{
      justifyContent: 'center',
      alignItems: 'center',
      backgroundColor: brandColor,
    }}>
      <div style={{transform: `scale(${scale})`, textAlign: 'center'}}>
        <Img src={logoUrl} style={{height: 80, marginBottom: 40}} />
        <div style={{
          fontSize: 40,
          fontWeight: 600,
          color: 'white',
          padding: '20px 50px',
          backgroundColor: 'rgba(255,255,255,0.2)',
          borderRadius: 30,
        }}>
          {ctaText}
        </div>
      </div>
    </AbsoluteFill>
  );
};
```

## Composition Registration

```tsx
<Composition
  id="Testimonial"
  component={Testimonial}
  durationInFrames={450}
  fps={30}
  width={1080}
  height={1920}
  defaultProps={{
    quote: 'This product completely changed my workflow. I save hours every week!',
    customerName: 'Maria Santos',
    customerTitle: 'Small Business Owner',
    customerPhotoUrl: staticFile('customer.jpg'),
    brandColor: '#10b981',
    logoUrl: staticFile('logo.png'),
    ctaText: 'Join 10,000+ Happy Customers',
  }}
/>
```
