← back to Prestige Car Wash Video

src/scenes/FcfsScene.tsx

64 lines

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

const FONT = 'Inter, "SF Pro Display", system-ui, -apple-system, sans-serif';

const Lane: React.FC<{ i: number; accent: string }> = ({ i, accent }) => {
  const f = useCurrentFrame();
  const start = 20 + i * 5;
  // a car glides up each of the 6 lanes, staggered, then loops
  const t = ((f - start) % 70) / 70;
  const carY = interpolate(t < 0 ? 0 : t, [0, 1], [560, -80]);
  const reveal = interpolate(f, [10 + i * 4, 30 + i * 4], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });
  return (
    <div style={{ position: 'relative', width: 150, height: 560, borderRadius: 16, overflow: 'hidden',
      background: 'linear-gradient(180deg,#0f1c30,#0a1220)', border: '1px solid rgba(255,255,255,0.06)', opacity: reveal }}>
      {/* lane dashes */}
      {[...Array(6)].map((_, k) => (
        <div key={k} style={{ position: 'absolute', left: '50%', top: 20 + k * 96, width: 8, height: 52, marginLeft: -4, borderRadius: 4, background: 'rgba(255,255,255,0.10)' }} />
      ))}
      {f > start && <div style={{ position: 'absolute', left: 0, right: 0, top: carY, textAlign: 'center', fontSize: 62 }}>🚗</div>}
      <div style={{ position: 'absolute', bottom: 12, left: 0, right: 0, textAlign: 'center', fontFamily: FONT, fontWeight: 800, fontSize: 22, color: accent }}>{i + 1}</div>
    </div>
  );
};

export const FcfsScene: React.FC<{ s: Scene }> = ({ s }) => {
  const f = useCurrentFrame();
  const { fps } = useVideoConfig();
  const pop = spring({ frame: f, fps, config: { damping: 200 } });
  const subO = interpolate(f, [16, 34], [0, 1], { extrapolateRight: 'clamp', extrapolateLeft: 'clamp' });
  const strike = interpolate(f, [26, 46], [0, 1], { easing: Easing.out(Easing.cubic), extrapolateRight: 'clamp', extrapolateLeft: 'clamp' });

  return (
    <AbsoluteFill style={{ alignItems: 'center', justifyContent: 'center' }}>
      {s.narr && <Audio src={staticFile(`audio/${s.narr}.wav`)} />}
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
        <div style={{ position: 'relative', opacity: pop, transform: `translateY(${interpolate(pop, [0, 1], [24, 0])}px)` }}>
          <div style={{ fontFamily: FONT, fontWeight: 900, fontSize: 92, color: '#f4f9ff', letterSpacing: 1 }}>
            No <span style={{ position: 'relative' }}>Appointments
              <span style={{ position: 'absolute', left: 0, top: '54%', height: 8, width: `${strike * 100}%`, background: '#fb7185', borderRadius: 6 }} />
            </span>
          </div>
        </div>
        <div style={{ opacity: subO, marginTop: 14, fontFamily: FONT, fontWeight: 800, fontSize: 46, color: s.accent, letterSpacing: 2 }}>
          First Come · First Served
        </div>

        <div style={{ display: 'flex', gap: 22, marginTop: 44 }}>
          {[...Array(6)].map((_, i) => <Lane key={i} i={i} accent={s.accent} />)}
        </div>

        <div style={{ marginTop: 40, display: 'flex', gap: 46, opacity: subO, fontFamily: FONT }}>
          {[['6', 'full lines'], ['Large', 'crew on deck'], ['0', 'wait to book']].map(([n, l]) => (
            <div key={l} style={{ textAlign: 'center' }}>
              <div style={{ fontWeight: 900, fontSize: 56, color: '#eaf2ff' }}>{n}</div>
              <div style={{ fontWeight: 600, fontSize: 24, color: '#9fb3cd', letterSpacing: 1 }}>{l}</div>
            </div>
          ))}
        </div>
      </div>
    </AbsoluteFill>
  );
};