← back to Prestige Car Wash Video

src/scenes/TipsScene.tsx

51 lines

import { AbsoluteFill, Img, Audio, staticFile, useCurrentFrame, interpolate, Easing } from 'remotion';
import type { Scene } from '../story';

const FONT = 'Inter, "SF Pro Display", system-ui, -apple-system, sans-serif';
const CARDS = ['marco', 'diego', 'andre', 'luis', 'kevin', 'sam'];

export const TipsScene: React.FC<{ s: Scene }> = ({ s }) => {
  const f = useCurrentFrame();
  const headO = interpolate(f, [4, 20], [0, 1], { extrapolateRight: 'clamp', extrapolateLeft: 'clamp' });
  // hero card (marco) slides in and its QR pulses; supporting cards fan behind
  return (
    <AbsoluteFill style={{ alignItems: 'center', justifyContent: 'center' }}>
      {s.narr && <Audio src={staticFile(`audio/${s.narr}.wav`)} />}

      <div style={{ position: 'absolute', top: 88, textAlign: 'center', opacity: headO }}>
        <div style={{ fontFamily: FONT, fontWeight: 800, fontSize: 22, letterSpacing: 6, textTransform: 'uppercase', color: s.accent }}>Tip the crew directly</div>
        <div style={{ marginTop: 12, fontFamily: FONT, fontWeight: 900, fontSize: 66, color: '#f4f9ff' }}>Every wash is done by a person</div>
        <div style={{ marginTop: 10, fontFamily: FONT, fontWeight: 500, fontSize: 30, color: '#b8c9e0' }}>Scan their card — 100% goes straight to them.</div>
      </div>

      {/* fanned supporting cards */}
      {CARDS.slice(1).map((c, i) => {
        const n = CARDS.length - 1;
        const spread = (i - (n - 1) / 2);
        const rot = spread * 7;
        const x = spread * 150;
        const rise = interpolate(f, [10 + i * 3, 34 + i * 3], [120, 0], { easing: Easing.out(Easing.cubic), extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });
        const o = interpolate(f, [10 + i * 3, 30 + i * 3], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });
        return (
          <Img key={c} src={staticFile(`cards/${c}.png`)}
            style={{ position: 'absolute', top: 300 + rise, width: 300, borderRadius: 20,
              transform: `translateX(${x}px) rotate(${rot}deg)`, opacity: o * 0.9,
              boxShadow: '0 30px 80px rgba(0,0,0,0.6)' }} />
        );
      })}

      {/* hero card front-and-center */}
      {(() => {
        const rise = interpolate(f, [22, 46], [140, 0], { easing: Easing.out(Easing.cubic), extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });
        const o = interpolate(f, [22, 40], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });
        const pulse = 1 + 0.02 * Math.sin(f / 6);
        return (
          <Img src={staticFile('cards/marco.png')}
            style={{ position: 'absolute', top: 250 + rise, width: 372, borderRadius: 24, opacity: o,
              transform: `scale(${pulse})`, boxShadow: '0 40px 110px rgba(0,0,0,0.75)', border: '1px solid rgba(255,255,255,0.08)' }} />
        );
      })()}
    </AbsoluteFill>
  );
};