feat(remotion): YC application video template + talking points

- Add YCAppVideo Remotion composition (1920x1080, 60s)
  - 3s intro card with founder name + company
  - 55s video placeholder with branded frame + lower thirds
  - 2s outro card with logo + tagline
- Update Root.tsx with new composition
- Add YC_APPLICATION_TALKING_POINTS.md with bullet points
  and recording tips per YC instructions
This commit is contained in:
Garfield
2026-05-13 14:54:48 -04:00
parent a5e4c55885
commit 660b7cdf18
3 changed files with 396 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
# Y Combinator Application Video — Talking Points
> **Rules from YC:** 1 minute. Founders talking. No script — use bullet points only. Talk like you're explaining to a friend.
---
## Your Bullet Points (≈60 seconds)
**[0:000:10] Who you are**
- "Hey, I'm Garfield Heron, solo founder of SquareMCP."
- "I'm a builder who's been in the trenches of API integrations for years."
**[0:100:25] The problem**
- "Every company now needs to post to TikTok, Instagram, LinkedIn, Twitter, WhatsApp, Telegram, Discord, Facebook, and email."
- "Right now that's 9 different APIs, 9 different auth flows, 9 different docs, 9 different failure modes."
- "Engineers spend weeks wiring this up. Then it breaks when TikTok changes their API or Meta deprecates a permission."
**[0:250:40] What SquareMCP is**
- "SquareMCP is one API that connects to all of them."
- "You authenticate once per platform through our dashboard, then call one endpoint: `publish_post` or `send_message`."
- "We handle the tokens, the rate limits, the retries, the API changes."
- "It's built on the Model Context Protocol — an open standard — so AI agents can use it too."
**[0:400:52] Traction / proof**
- "We've got the full TikTok sandbox working, Facebook Graph API, and SMTP/email."
- "We're live at squaremcp.com with per-user credential storage, usage tracking, and invoice-based billing."
- "TikTok app review is in progress."
**[0:521:00] Why you, why now**
- "I lived this pain. I'm the exact person to fix it."
- "AI agents need to post to social too — and they need a standard way to do it. MCP is that standard."
- "We're building the infrastructure layer that every AI-native company will need."
---
## Recording Tips
1. **Use your phone or laptop webcam** — 1080p is plenty. Good lighting matters more than camera quality.
2. **Look at the lens, not the screen.** It feels like eye contact.
3. **Don't memorize.** Glance at these bullet points, then talk naturally. Stumbling is fine — YC prefers real over polished.
4. **One continuous take.** No cuts, no B-roll, no music. Just you talking.
5. **Background:** clean wall, or a desk with a monitor showing your product. Nothing distracting.
## After Recording
1. Export your raw video as `my-recording.mp4` (1920×1080 ideally)
2. Replace the placeholder in `YCAppVideo.tsx` with an `<OffthreadVideo>` component pointing to your file
3. Re-render: `npx remotion render YCAppVideo out/final-yc-video.mp4`
---
*Good luck!* 🚀

View File

@@ -2,6 +2,7 @@ import "./index.css";
import { Composition } from "remotion";
import { SquareMCPLinkedIn } from "./SquareMCPLinkedIn";
import { SquareMCPHeroLoop } from "./SquareMCPHeroLoop";
import { YCAppVideo } from "./YCAppVideo";
import {
SquareMCPTikTokCTA,
SquareMCPTikTokDemo,
@@ -78,6 +79,14 @@ export const RemotionRoot = () => {
width={1080}
height={1920}
/>
<Composition
id="YCAppVideo"
component={YCAppVideo}
durationInFrames={60 * 30}
fps={30}
width={1920}
height={1080}
/>
</>
);
};

View File

@@ -0,0 +1,335 @@
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from "remotion";
import { COLORS, FONT, SPRING_CFG } from "./styles";
// ─── CONFIG ──────────────────────────────────────────────────────────
const INTRO_DURATION = 3; // seconds
const OUTRO_DURATION = 2; // seconds
const TOTAL_DURATION = 60; // seconds (YC wants ~1 min)
// ─── INTRO CARD ──────────────────────────────────────────────────────
const IntroCard = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const nameY = spring({
frame,
fps,
config: SPRING_CFG,
from: 60,
to: 0,
delay: 0,
});
const companyY = spring({
frame,
fps,
config: SPRING_CFG,
from: 40,
to: 0,
delay: 5,
});
const taglineOpacity = interpolate(
frame,
[1.5 * fps, 2 * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
const fadeOut = interpolate(
frame,
[(INTRO_DURATION - 0.4) * fps, INTRO_DURATION * fps],
[1, 0],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
return (
<AbsoluteFill
style={{
background: `radial-gradient(ellipse at 50% 40%, ${COLORS.bgCard} 0%, ${COLORS.bg} 70%)`,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
opacity: fadeOut,
fontFamily: FONT,
}}
>
{/* Accent glow */}
<div
style={{
position: "absolute",
width: 400,
height: 400,
borderRadius: "50%",
background: `radial-gradient(circle, ${COLORS.accentGlow} 0%, transparent 70%)`,
top: "30%",
left: "50%",
transform: "translate(-50%, -50%)",
}}
/>
{/* Founder name */}
<div
style={{
fontSize: 72,
fontWeight: 800,
color: COLORS.text,
textAlign: "center",
letterSpacing: "-0.02em",
transform: `translateY(${nameY}px)`,
textShadow: `0 0 60px ${COLORS.accentGlow}`,
}}
>
Garfield Heron
</div>
{/* Company name */}
<div
style={{
fontSize: 40,
fontWeight: 700,
color: COLORS.accentLight,
marginTop: 16,
transform: `translateY(${companyY}px)`,
display: "flex",
alignItems: "center",
gap: 12,
}}
>
<span style={{ color: COLORS.accent }}></span>
SquareMCP
</div>
{/* Subtitle */}
<div
style={{
fontSize: 20,
fontWeight: 400,
color: COLORS.textSecondary,
marginTop: 24,
opacity: taglineOpacity,
}}
>
Y Combinator Application
</div>
</AbsoluteFill>
);
};
// ─── VIDEO PLACEHOLDER (subtle frame for your recording) ─────────────
const VideoFrame = ({ children }: { children?: React.ReactNode }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// Fade in from intro
const fadeIn = interpolate(
frame,
[INTRO_DURATION * fps, (INTRO_DURATION + 0.5) * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
// Fade out to outro
const fadeOut = interpolate(
frame,
[(TOTAL_DURATION - OUTRO_DURATION - 0.5) * fps, (TOTAL_DURATION - OUTRO_DURATION) * fps],
[1, 0],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
return (
<AbsoluteFill
style={{
background: "#000000",
opacity: fadeIn * fadeOut,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{/* Corner accents */}
<div
style={{
position: "absolute",
inset: 20,
border: `1px solid ${COLORS.borderBlue}`,
borderRadius: 8,
pointerEvents: "none",
}}
/>
{/* Corner dots */}
{[
{ top: 16, left: 16 },
{ top: 16, right: 16 },
{ bottom: 16, left: 16 },
{ bottom: 16, right: 16 },
].map((pos, i) => (
<div
key={i}
style={{
position: "absolute",
width: 6,
height: 6,
borderRadius: "50%",
background: COLORS.accent,
...pos,
}}
/>
))}
{/* Lower third - name + company */}
<div
style={{
position: "absolute",
bottom: 40,
left: 40,
right: 40,
display: "flex",
justifyContent: "space-between",
alignItems: "flex-end",
fontFamily: FONT,
pointerEvents: "none",
}}
>
<div>
<div style={{ fontSize: 18, fontWeight: 700, color: COLORS.text }}>
Garfield Heron
</div>
<div style={{ fontSize: 14, fontWeight: 400, color: COLORS.textSecondary, marginTop: 2 }}>
Founder, SquareMCP
</div>
</div>
<div style={{ fontSize: 14, fontWeight: 600, color: COLORS.accentLight }}>
squaremcp.com
</div>
</div>
{/* Placeholder text (remove when you overlay your actual video) */}
{!children && (
<div
style={{
fontFamily: FONT,
color: COLORS.textSecondary,
fontSize: 24,
textAlign: "center",
}}
>
<div>YOUR RECORDING GOES HERE</div>
<div style={{ fontSize: 16, marginTop: 12, opacity: 0.6 }}>
Record yourself talking, then overlay it in Remotion
</div>
</div>
)}
{children}
</AbsoluteFill>
);
};
// ─── OUTRO CARD ──────────────────────────────────────────────────────
const OutroCard = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const outroStart = (TOTAL_DURATION - OUTRO_DURATION) * fps;
const localFrame = frame - outroStart;
const scale = spring({
frame: localFrame,
fps,
config: SPRING_CFG,
from: 0.9,
to: 1,
});
const opacity = interpolate(
localFrame,
[0, 0.5 * fps],
[0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
);
return (
<AbsoluteFill
style={{
background: COLORS.bg,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
opacity,
transform: `scale(${scale})`,
fontFamily: FONT,
}}
>
{/* Logo mark */}
<div
style={{
width: 64,
height: 64,
borderRadius: 16,
background: COLORS.accent,
display: "flex",
alignItems: "center",
justifyContent: "center",
fontSize: 28,
fontWeight: 800,
color: "#fff",
}}
>
</div>
<div
style={{
fontSize: 48,
fontWeight: 800,
color: COLORS.text,
marginTop: 24,
letterSpacing: "-0.02em",
}}
>
SquareMCP
</div>
<div
style={{
fontSize: 22,
fontWeight: 400,
color: COLORS.textSecondary,
marginTop: 12,
}}
>
One API. Every Platform.
</div>
<div
style={{
fontSize: 16,
color: COLORS.accentLight,
marginTop: 32,
fontWeight: 600,
}}
>
squaremcp.com
</div>
</AbsoluteFill>
);
};
// ─── MAIN COMPOSITION ────────────────────────────────────────────────
export const YCAppVideo = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const showIntro = frame < INTRO_DURATION * fps;
const showOutro = frame >= (TOTAL_DURATION - OUTRO_DURATION) * fps;
return (
<AbsoluteFill style={{ background: "#000" }}>
{showIntro && <IntroCard />}
{!showIntro && !showOutro && <VideoFrame />}
{showOutro && <OutroCard />}
</AbsoluteFill>
);
};