← back to Crcp Pitch Video
src/Video.tsx
340 lines
import React from 'react';
import {
AbsoluteFill, Sequence, useCurrentFrame, useVideoConfig, interpolate, spring, Easing,
} from 'remotion';
export const FPS = 30;
export const TOTAL_FRAMES = 5400; // 180s
// ── palette ──
const C = {
bg: '#0a0d13', bg2: '#11151f', card: '#161b26', line: '#2a3242',
ink: '#EAECEF', mut: '#8A93A2', gold: '#C8A24B', goldD: '#9c7a2f',
blue: '#58a6ff', green: '#6BCB77', red: '#f0616a',
};
const SERIF = 'Georgia, "Times New Roman", serif';
const SANS = '-apple-system, "Helvetica Neue", Arial, sans-serif';
// ── helpers ──
const useFade = (inAt: number, dur = 18, outAt?: number, outDur = 18) => {
const f = useCurrentFrame();
let o = interpolate(f, [inAt, inAt + dur], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });
if (outAt != null) o *= interpolate(f, [outAt, outAt + outDur], [1, 0], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });
return o;
};
const useRise = (inAt: number, dist = 40) => {
const f = useCurrentFrame();
const p = interpolate(f, [inAt, inAt + 22], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.out(Easing.cubic) });
return (1 - p) * dist;
};
const Bg: React.FC<{ tone?: string }> = ({ tone = C.bg }) => {
const f = useCurrentFrame();
const drift = interpolate(f, [0, 300], [0, 30]);
return (
<AbsoluteFill style={{ background: `radial-gradient(1200px 700px at ${50 + drift / 6}% 18%, ${C.bg2} 0%, ${tone} 62%)` }}>
<AbsoluteFill style={{
backgroundImage: `linear-gradient(${C.line}22 1px, transparent 1px), linear-gradient(90deg, ${C.line}22 1px, transparent 1px)`,
backgroundSize: '64px 64px', opacity: 0.5,
}} />
<AbsoluteFill style={{ background: `linear-gradient(180deg, transparent 55%, ${tone} 100%)` }} />
</AbsoluteFill>
);
};
const Kicker: React.FC<{ children: React.ReactNode; delay?: number; color?: string }> = ({ children, delay = 0, color = C.gold }) => (
<div style={{
fontFamily: SANS, fontSize: 22, letterSpacing: 6, textTransform: 'uppercase', color,
opacity: useFade(delay), transform: `translateY(${useRise(delay, 20)}px)`, fontWeight: 700,
}}>{children}</div>
);
const Counter: React.FC<{ to: number; delay: number; fmt?: (n: number) => string }> = ({ to, delay, fmt }) => {
const f = useCurrentFrame();
const v = Math.round(interpolate(f, [delay, delay + 55], [0, to], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.out(Easing.cubic) }));
return <>{fmt ? fmt(v) : v.toLocaleString()}</>;
};
// ═══════════════ SCENE 1 — TITLE ═══════════════
const S1: React.FC = () => {
const { fps } = useVideoConfig();
const f = useCurrentFrame();
const logo = spring({ frame: f - 4, fps, config: { damping: 14, mass: 0.8 } });
return (
<AbsoluteFill style={{ justifyContent: 'center', alignItems: 'center', textAlign: 'center' }}>
<Bg />
<div style={{ transform: `scale(${0.9 + logo * 0.1})`, opacity: useFade(4) }}>
<div style={{
fontFamily: SERIF, fontSize: 46, color: C.gold, letterSpacing: 10, fontWeight: 700,
border: `2px solid ${C.gold}`, borderRadius: 14, padding: '14px 30px', display: 'inline-block',
}}>CRCP</div>
</div>
<div style={{ fontFamily: SERIF, fontSize: 84, color: C.ink, marginTop: 34, fontWeight: 700, letterSpacing: 1, opacity: useFade(24), transform: `translateY(${useRise(24)}px)` }}>
Every licensed agent.<br />America's priciest markets.
</div>
<div style={{ fontFamily: SANS, fontSize: 30, color: C.mut, marginTop: 30, opacity: useFade(54), maxWidth: 1100 }}>
The prospecting platform for loan officers, escrow & title professionals.
</div>
<div style={{ fontFamily: SANS, fontSize: 22, color: C.gold, marginTop: 46, letterSpacing: 3, opacity: useFade(80) }}>
crcp.agentabrams.com
</div>
</AbsoluteFill>
);
};
// ═══════════════ SCENE 2 — THE PROBLEM ═══════════════
const S2: React.FC = () => {
const lines = [
'Your business runs on ONE thing:',
'relationships with the real-estate agents who close deals.',
];
return (
<AbsoluteFill style={{ justifyContent: 'center', paddingLeft: 150, paddingRight: 150 }}>
<Bg />
<Kicker delay={4}>The reality</Kicker>
<div style={{ marginTop: 30 }}>
{lines.map((t, i) => (
<div key={i} style={{
fontFamily: SERIF, fontSize: i === 0 ? 46 : 60, color: i === 0 ? C.mut : C.ink, lineHeight: 1.2,
marginTop: i ? 10 : 0, fontWeight: i ? 700 : 400,
opacity: useFade(20 + i * 26), transform: `translateY(${useRise(20 + i * 26)}px)`,
}}>{t}</div>
))}
</div>
<div style={{ fontFamily: SANS, fontSize: 32, color: C.gold, marginTop: 54, opacity: useFade(96), lineHeight: 1.5 }}>
But <b>which</b> agents? <b>Where?</b> And how do you reach them<br />before every other rep in town does?
</div>
</AbsoluteFill>
);
};
// ═══════════════ SCENE 3 — WHAT IT IS ═══════════════
const Stat: React.FC<{ big: React.ReactNode; label: string; delay: number }> = ({ big, label, delay }) => (
<div style={{ opacity: useFade(delay), transform: `translateY(${useRise(delay, 30)}px)`, textAlign: 'center' }}>
<div style={{ fontFamily: SERIF, fontSize: 96, color: C.gold, fontWeight: 700, lineHeight: 1 }}>{big}</div>
<div style={{ fontFamily: SANS, fontSize: 24, color: C.mut, marginTop: 12, letterSpacing: 2, textTransform: 'uppercase' }}>{label}</div>
</div>
);
const S3: React.FC = () => {
const cities = ['Beverly Hills', 'Manhattan', 'Aspen', 'Naples', 'Silicon Valley', 'Greenwich', 'Malibu', 'Palm Beach', 'The Hamptons', 'Vail', 'Newport Beach', 'Telluride', 'Miami', 'San Francisco'];
return (
<AbsoluteFill style={{ justifyContent: 'center', alignItems: 'center' }}>
<Bg />
<Kicker delay={2}>Meet CRCP</Kicker>
<div style={{ display: 'flex', gap: 120, marginTop: 44 }}>
<Stat big={<Counter to={355354} delay={16} />} label="Licensed agents" delay={12} />
<Stat big={<Counter to={21} delay={16} />} label="Elite markets" delay={22} />
<Stat big={<><Counter to={20} delay={16} /></>} label="Priciest US cities" delay={32} />
</div>
<div style={{ fontFamily: SANS, fontSize: 26, color: C.ink, marginTop: 40, opacity: useFade(60), maxWidth: 1300, textAlign: 'center', lineHeight: 1.5 }}>
Backed by <b style={{ color: C.green }}>government license data</b> — real, verified licenses from the
DRE, DOS, DBPR & more. Not scraped guesses.
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 14, justifyContent: 'center', maxWidth: 1400, marginTop: 40 }}>
{cities.map((c, i) => {
const d = 78 + i * 5;
return (
<div key={c} style={{
fontFamily: SANS, fontSize: 24, color: C.gold, border: `1px solid ${C.goldD}`,
borderRadius: 30, padding: '10px 22px', background: `${C.gold}12`,
opacity: useFade(d), transform: `translateY(${useRise(d, 18)}px)`,
}}>{c}</div>
);
})}
</div>
<div style={{ fontFamily: SANS, fontSize: 24, color: C.mut, marginTop: 40, opacity: useFade(170), letterSpacing: 1 }}>
Search any market → every agent, their brokerage, license & listings.
</div>
</AbsoluteFill>
);
};
// ═══════════════ SCENE 4 — WHY IT'S VALUABLE (by role) ═══════════════
const RoleCard: React.FC<{ icon: string; role: string; line: string; delay: number }> = ({ icon, role, line, delay }) => {
const { fps } = useVideoConfig();
const f = useCurrentFrame();
const s = spring({ frame: f - delay, fps, config: { damping: 15 } });
return (
<div style={{
background: C.card, border: `1px solid ${C.line}`, borderRadius: 18, padding: '30px 34px', width: 1180,
display: 'flex', gap: 26, alignItems: 'center',
opacity: interpolate(s, [0, 1], [0, 1]), transform: `translateX(${(1 - s) * -60}px)`,
}}>
<div style={{ fontSize: 60, width: 78, textAlign: 'center' }}>{icon}</div>
<div>
<div style={{ fontFamily: SANS, fontSize: 30, color: C.gold, fontWeight: 700, letterSpacing: 1 }}>{role}</div>
<div style={{ fontFamily: SANS, fontSize: 27, color: C.ink, marginTop: 8, lineHeight: 1.4 }}>{line}</div>
</div>
</div>
);
};
const S4: React.FC = () => (
<AbsoluteFill style={{ justifyContent: 'center', alignItems: 'center' }}>
<Bg />
<div style={{ opacity: useFade(2) }}><Kicker delay={2}>Why it matters to you</Kicker></div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 26, marginTop: 44 }}>
<RoleCard icon="🏦" role="LOAN OFFICERS" delay={20}
line="Agents send you borrowers. Target the top producers in luxury markets — where one deal is a jumbo loan." />
<RoleCard icon="📜" role="ESCROW OFFICERS" delay={90}
line="Agents choose escrow. Get in front of the highest-volume agents before your competitor does." />
<RoleCard icon="🏛️" role="TITLE REPS" delay={160}
line="Title follows relationships. Build yours with the agents controlling the priciest inventory in America." />
</div>
<div style={{ fontFamily: SERIF, fontSize: 34, color: C.gold, marginTop: 48, opacity: useFade(240), fontStyle: 'italic' }}>
One platform. Every deal-maker. Before anyone else finds them.
</div>
</AbsoluteFill>
);
// ═══════════════ SCENE 5 — HOW TO APPROACH ═══════════════
const Channel: React.FC<{ icon: string; name: string; tip: string; delay: number }> = ({ icon, name, tip, delay }) => {
const { fps } = useVideoConfig();
const f = useCurrentFrame();
const s = spring({ frame: f - delay, fps, config: { damping: 16, mass: 0.9 } });
return (
<div style={{
background: C.card, border: `1px solid ${C.line}`, borderRadius: 16, padding: '26px 22px', width: 400, height: 300,
opacity: interpolate(s, [0, 1], [0, 1]), transform: `scale(${interpolate(s, [0, 1], [0.85, 1])})`,
display: 'flex', flexDirection: 'column',
}}>
<div style={{ fontSize: 52 }}>{icon}</div>
<div style={{ fontFamily: SANS, fontSize: 30, color: C.blue, fontWeight: 700, marginTop: 12, letterSpacing: 1 }}>{name}</div>
<div style={{ fontFamily: SANS, fontSize: 23, color: C.ink, marginTop: 12, lineHeight: 1.45 }}>{tip}</div>
</div>
);
};
const S5: React.FC = () => (
<AbsoluteFill style={{ justifyContent: 'center', alignItems: 'center' }}>
<Bg />
<Kicker delay={2}>The outreach playbook</Kicker>
<div style={{ fontFamily: SERIF, fontSize: 44, color: C.ink, marginTop: 18, opacity: useFade(14) }}>
Four channels. One relationship.
</div>
<div style={{ display: 'flex', gap: 22, marginTop: 40, flexWrap: 'wrap', justifyContent: 'center', maxWidth: 1720 }}>
<Channel icon="📞" name="CALL" delay={30} tip="Warm, personal, fast. Reference a recent listing of theirs. Reserve for your highest-value agents." />
<Channel icon="✉️" name="EMAIL" delay={54} tip="Scalable. Lead with value — a market stat or co-marketing offer. Short. One ask. Follow up twice." />
<Channel icon="✉️📮" name="POSTCARD" delay={78} tip="Cuts through digital noise. Luxury agents notice physical mail. Branded, monthly, on-message." />
<Channel icon="in" name="LINKEDIN" delay={102} tip="Connect + engage before pitching. Comment on their wins. Relationship-first, never a cold pitch." />
</div>
<div style={{
fontFamily: SANS, fontSize: 27, color: C.gold, marginTop: 46, opacity: useFade(150),
background: `${C.gold}10`, border: `1px solid ${C.goldD}`, borderRadius: 40, padding: '14px 34px',
}}>
Best cadence: <b>LinkedIn connect → value email → follow-up call → postcard reminder.</b>
</div>
</AbsoluteFill>
);
// ═══════════════ SCENE 6 — CONTACT + CTA ═══════════════
const S6: React.FC = () => {
const f = useCurrentFrame();
const rows = [
['On every record', 'Name · brokerage · license # · city · listings'],
['Enrich for direct contact', 'Brokerage site → LinkedIn → skip-trace for phone/email'],
['Start here', 'The agents closing the biggest deals in your market'],
];
return (
<AbsoluteFill style={{ justifyContent: 'center', alignItems: 'center', textAlign: 'center' }}>
<Bg />
<Kicker delay={2}>Getting the contact info</Kicker>
<div style={{ marginTop: 34, display: 'flex', flexDirection: 'column', gap: 14 }}>
{rows.map((r, i) => (
<div key={i} style={{
display: 'flex', gap: 20, alignItems: 'center', justifyContent: 'center',
opacity: useFade(14 + i * 16), transform: `translateY(${useRise(14 + i * 16, 22)}px)`,
}}>
<span style={{ fontFamily: SANS, fontSize: 24, color: C.gold, fontWeight: 700, width: 340, textAlign: 'right' }}>{r[0]}</span>
<span style={{ color: C.line }}>│</span>
<span style={{ fontFamily: SANS, fontSize: 26, color: C.ink, width: 640, textAlign: 'left' }}>{r[1]}</span>
</div>
))}
</div>
<div style={{ fontFamily: SERIF, fontSize: 62, color: C.ink, marginTop: 60, fontWeight: 700, opacity: useFade(80) }}>
Reach the right agents first.
</div>
<div style={{
fontFamily: SANS, fontSize: 30, color: C.bg, marginTop: 34, opacity: useFade(100), fontWeight: 700,
background: C.gold, borderRadius: 12, padding: '16px 40px', letterSpacing: 2,
}}>
crcp.agentabrams.com
</div>
</AbsoluteFill>
);
};
// ═══════════════ 60-SECOND SOCIAL CUT ═══════════════
export const SHORT_FRAMES = 1800; // 60s
const ShortStats: React.FC = () => {
const cities = ['Beverly Hills', 'Manhattan', 'Aspen', 'Naples', 'Greenwich', 'Malibu', 'Palm Beach', 'The Hamptons', 'Vail', 'Miami'];
return (
<AbsoluteFill style={{ justifyContent: 'center', alignItems: 'center' }}>
<Bg />
<Kicker delay={2}>Meet CRCP</Kicker>
<div style={{ display: 'flex', gap: 90, marginTop: 34 }}>
<Stat big={<Counter to={355354} delay={10} />} label="Licensed agents" delay={8} />
<Stat big={<Counter to={20} delay={10} />} label="Priciest US cities" delay={16} />
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 12, justifyContent: 'center', maxWidth: 1300, marginTop: 44 }}>
{cities.map((c, i) => {
const d = 40 + i * 6;
return <div key={c} style={{ fontFamily: SANS, fontSize: 24, color: C.gold, border: `1px solid ${C.goldD}`, borderRadius: 30, padding: '9px 20px', background: `${C.gold}12`, opacity: useFade(d), transform: `translateY(${useRise(d, 16)}px)` }}>{c}</div>;
})}
</div>
<div style={{ fontFamily: SANS, fontSize: 26, color: C.ink, marginTop: 42, opacity: useFade(120), maxWidth: 1200, textAlign: 'center' }}>
Every agent in America's priciest markets — <b style={{ color: C.green }}>government-verified.</b>
</div>
</AbsoluteFill>
);
};
const ShortRoles: React.FC = () => (
<AbsoluteFill style={{ justifyContent: 'center', alignItems: 'center' }}>
<Bg />
<Kicker delay={2}>Built for you</Kicker>
<div style={{ display: 'flex', flexDirection: 'column', gap: 22, marginTop: 40 }}>
<RoleCard icon="🏦" role="LOAN OFFICERS" delay={14} line="Target the top producers — where one deal is a jumbo loan." />
<RoleCard icon="📜" role="ESCROW OFFICERS" delay={40} line="Reach the highest-volume agents before your competitor does." />
<RoleCard icon="🏛️" role="TITLE REPS" delay={66} line="Build relationships with the agents controlling the priciest inventory." />
</div>
</AbsoluteFill>
);
const ShortChannels: React.FC = () => (
<AbsoluteFill style={{ justifyContent: 'center', alignItems: 'center' }}>
<Bg />
<Kicker delay={2}>Reach them</Kicker>
<div style={{ display: 'flex', gap: 20, marginTop: 40 }}>
{[['📞', 'CALL'], ['✉️', 'EMAIL'], ['📮', 'POSTCARD'], ['in', 'LINKEDIN']].map(([ic, nm], i) => (
<div key={nm} style={{ background: C.card, border: `1px solid ${C.line}`, borderRadius: 16, padding: '26px 30px', textAlign: 'center', opacity: useFade(14 + i * 8), transform: `scale(${interpolate(useFade(14 + i * 8), [0, 1], [0.85, 1])})` }}>
<div style={{ fontSize: 46 }}>{ic}</div>
<div style={{ fontFamily: SANS, fontSize: 26, color: C.blue, fontWeight: 700, marginTop: 8 }}>{nm}</div>
</div>
))}
</div>
<div style={{ fontFamily: SANS, fontSize: 26, color: C.gold, marginTop: 40, opacity: useFade(70) }}>
LinkedIn → email → call → postcard.
</div>
</AbsoluteFill>
);
export const CRCPShort: React.FC = () => (
<AbsoluteFill style={{ background: C.bg }}>
<Sequence from={0} durationInFrames={150}><S1 /></Sequence>
<Sequence from={150} durationInFrames={540}><ShortStats /></Sequence>
<Sequence from={690} durationInFrames={600}><ShortRoles /></Sequence>
<Sequence from={1290} durationInFrames={300}><ShortChannels /></Sequence>
<Sequence from={1590} durationInFrames={210}><S6 /></Sequence>
</AbsoluteFill>
);
// ═══════════════ ROOT SEQUENCER ═══════════════
export const CRCPPitch: React.FC = () => {
return (
<AbsoluteFill style={{ background: C.bg }}>
<Sequence from={0} durationInFrames={390}><S1 /></Sequence>
<Sequence from={390} durationInFrames={690}><S2 /></Sequence>
<Sequence from={1080} durationInFrames={1290}><S3 /></Sequence>
<Sequence from={2370} durationInFrames={1440}><S4 /></Sequence>
<Sequence from={3810} durationInFrames={1260}><S5 /></Sequence>
<Sequence from={5070} durationInFrames={330}><S6 /></Sequence>
</AbsoluteFill>
);
};