← back to Prestige Car Wash Video
src/Video.tsx
118 lines
import { AbsoluteFill, Sequence, useCurrentFrame, useVideoConfig, interpolate } from 'remotion';
import { SECTIONS } from './sections';
import { Background } from './Background';
import { BrowserShot } from './BrowserShot';
import { Caption } from './Caption';
import { Card } from './Card';
const FONT = 'Inter, "SF Pro Display", system-ui, -apple-system, sans-serif';
// fade each section in/out over the persistent background
const FadeWrap: React.FC<{ dur: number; children: React.ReactNode }> = ({ dur, children }) => {
const f = useCurrentFrame();
const o = interpolate(f, [0, 12, dur - 10, dur], [0, 1, 1, 0], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
return <AbsoluteFill style={{ opacity: o }}>{children}</AbsoluteFill>;
};
export const PrestigeShowcase: React.FC = () => {
const frame = useCurrentFrame();
const { durationInFrames } = useVideoConfig();
const offsets: number[] = [];
let acc = 0;
for (const s of SECTIONS) { offsets.push(acc); acc += s.frames; }
let active = 0;
for (let i = 0; i < SECTIONS.length; i++) if (frame >= offsets[i]) active = i;
const accent = SECTIONS[active].accent;
const shotIndex = SECTIONS.slice(0, active + 1).filter((s) => s.kind === 'shot').length;
const shotTotal = SECTIONS.filter((s) => s.kind === 'shot').length;
return (
<AbsoluteFill style={{ backgroundColor: '#060c16' }}>
<Background accent={accent} />
{SECTIONS.map((s, i) => (
<Sequence key={s.id} from={offsets[i]} durationInFrames={s.frames} name={s.title}>
<FadeWrap dur={s.frames}>
{s.kind === 'card' ? (
<Card s={s} />
) : (
<>
<BrowserShot s={s} />
<Caption s={s} index={i} total={SECTIONS.length} />
</>
)}
</FadeWrap>
</Sequence>
))}
{/* top progress bar */}
<div style={{ position: 'absolute', top: 0, left: 0, right: 0, height: 6, background: 'rgba(255,255,255,0.08)' }}>
<div
style={{
height: 6,
width: `${(frame / durationInFrames) * 100}%`,
background: accent,
boxShadow: `0 0 16px ${accent}`,
}}
/>
</div>
{/* section counter (only during shot sections) */}
{SECTIONS[active].kind === 'shot' && (
<div
style={{
position: 'absolute',
top: 34,
right: 54,
fontFamily: FONT,
fontWeight: 700,
fontSize: 24,
color: '#8ea6c4',
letterSpacing: 2,
}}
>
{String(shotIndex).padStart(2, '0')}
<span style={{ opacity: 0.4 }}> / {String(shotTotal).padStart(2, '0')}</span>
</div>
)}
{/* persistent wordmark */}
<div
style={{
position: 'absolute',
top: 30,
left: 54,
display: 'flex',
alignItems: 'center',
gap: 12,
fontFamily: FONT,
fontWeight: 800,
fontSize: 24,
color: '#e8f1ff',
letterSpacing: 0.5,
}}
>
<span
style={{
display: 'inline-flex',
width: 34,
height: 34,
borderRadius: 9,
background: 'linear-gradient(135deg,#38bdf8,#2563eb)',
alignItems: 'center',
justifyContent: 'center',
fontSize: 18,
}}
>
🚗
</span>
Prestige<span style={{ opacity: 0.5, fontWeight: 600 }}>Car Wash</span>
</div>
</AbsoluteFill>
);
};