feat(remotion): WhatsApp Cloud API demo video for Meta app review
15s landscape (1920x1080) split-screen: left shows SquareMCP chat prompt + animated cURL command + 200 response with wamid; right shows a rendered WhatsApp phone UI with the message bubble appearing and blue double-checkmarks. Also adds transparent-background logo PNG for Meta Tech Provider icon upload. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
BIN
product/site/squaremcp-logo-transparent.png
Normal file
BIN
product/site/squaremcp-logo-transparent.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
product/site/whatsapp-demo-video.mp4
Normal file
BIN
product/site/whatsapp-demo-video.mp4
Normal file
Binary file not shown.
@@ -11,6 +11,7 @@ import {
|
|||||||
SquareMCPTikTokProblem,
|
SquareMCPTikTokProblem,
|
||||||
SquareMCPTikTokProof,
|
SquareMCPTikTokProof,
|
||||||
} from "./SquareMCPTikTok";
|
} from "./SquareMCPTikTok";
|
||||||
|
import { SquareMCPWhatsApp } from "./SquareMCPWhatsApp";
|
||||||
|
|
||||||
export const RemotionRoot = () => {
|
export const RemotionRoot = () => {
|
||||||
return (
|
return (
|
||||||
@@ -87,6 +88,14 @@ export const RemotionRoot = () => {
|
|||||||
width={1920}
|
width={1920}
|
||||||
height={1080}
|
height={1080}
|
||||||
/>
|
/>
|
||||||
|
<Composition
|
||||||
|
id="SquareMCPWhatsApp"
|
||||||
|
component={SquareMCPWhatsApp}
|
||||||
|
durationInFrames={15 * 30}
|
||||||
|
fps={30}
|
||||||
|
width={1920}
|
||||||
|
height={1080}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
27
videos/remotion-demo/src/SquareMCPWhatsApp.tsx
Normal file
27
videos/remotion-demo/src/SquareMCPWhatsApp.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { AbsoluteFill, Sequence, useVideoConfig } from "remotion";
|
||||||
|
import { WhatsAppBackground } from "./scenes/whatsapp/WhatsAppBackground";
|
||||||
|
import { WhatsAppIntro } from "./scenes/whatsapp/WhatsAppIntro";
|
||||||
|
import { WhatsAppSplitScreen } from "./scenes/whatsapp/WhatsAppSplitScreen";
|
||||||
|
|
||||||
|
const Shell = ({ children }: { children: React.ReactNode }) => (
|
||||||
|
<AbsoluteFill>
|
||||||
|
<WhatsAppBackground />
|
||||||
|
{children}
|
||||||
|
</AbsoluteFill>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Total: 3s intro + 12s split-screen = 15s @ 30fps = 450 frames
|
||||||
|
export const SquareMCPWhatsApp = () => {
|
||||||
|
const { fps } = useVideoConfig();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Shell>
|
||||||
|
<Sequence durationInFrames={3 * fps}>
|
||||||
|
<WhatsAppIntro />
|
||||||
|
</Sequence>
|
||||||
|
<Sequence from={3 * fps}>
|
||||||
|
<WhatsAppSplitScreen />
|
||||||
|
</Sequence>
|
||||||
|
</Shell>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { AbsoluteFill } from "remotion";
|
||||||
|
|
||||||
|
export const WhatsAppBackground = () => (
|
||||||
|
<AbsoluteFill
|
||||||
|
style={{
|
||||||
|
background: "linear-gradient(160deg, #0a1a10 0%, #060d0a 50%, #030806 100%)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Subtle grid */}
|
||||||
|
<AbsoluteFill
|
||||||
|
style={{
|
||||||
|
backgroundImage:
|
||||||
|
"linear-gradient(rgba(37,211,102,0.04) 1px, transparent 1px), linear-gradient(90deg, rgba(37,211,102,0.04) 1px, transparent 1px)",
|
||||||
|
backgroundSize: "64px 64px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/* Glow */}
|
||||||
|
<AbsoluteFill
|
||||||
|
style={{
|
||||||
|
background:
|
||||||
|
"radial-gradient(ellipse 60% 40% at 50% 50%, rgba(37,211,102,0.07) 0%, transparent 70%)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</AbsoluteFill>
|
||||||
|
);
|
||||||
88
videos/remotion-demo/src/scenes/whatsapp/WhatsAppIntro.tsx
Normal file
88
videos/remotion-demo/src/scenes/whatsapp/WhatsAppIntro.tsx
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import { AbsoluteFill, spring, useCurrentFrame, useVideoConfig } from "remotion";
|
||||||
|
import { FONT, SPRING_CFG } from "../../styles";
|
||||||
|
|
||||||
|
const WA_GREEN = "#25D366";
|
||||||
|
|
||||||
|
const WhatsAppIcon = ({ size }: { size: number }) => (
|
||||||
|
<svg width={size} height={size} viewBox="0 0 64 64" fill="none">
|
||||||
|
<circle cx="32" cy="32" r="32" fill={WA_GREEN} />
|
||||||
|
<path
|
||||||
|
d="M32 10C19.85 10 10 19.85 10 32c0 3.9 1.05 7.55 2.87 10.7L10 54l11.6-2.83A21.87 21.87 0 0 0 32 54c12.15 0 22-9.85 22-22S44.15 10 32 10zm0 4c9.94 0 18 8.06 18 18s-8.06 18-18 18a17.93 17.93 0 0 1-9.1-2.47l-.65-.39-6.75 1.65 1.68-6.57-.43-.68A17.93 17.93 0 0 1 14 32c0-9.94 8.06-18 18-18zm-5.2 9.5c-.38 0-1 .14-1.52.7-.52.57-2 1.96-2 4.78s2.05 5.55 2.33 5.93c.29.38 4 6.2 9.77 8.45 1.36.52 2.42.83 3.24 1.06 1.36.38 2.6.33 3.58.2 1.09-.14 3.35-1.37 3.83-2.69.47-1.33.47-2.47.33-2.7-.14-.24-.52-.38-.9-.57l-3.96-1.95c-.38-.19-.67-.28-.95.29-.29.57-1.1 1.38-1.35 1.67-.24.29-.48.33-.86.14-.38-.19-1.6-.59-3.04-1.88-1.12-1-1.88-2.24-2.1-2.62-.22-.38-.02-.58.17-.77.17-.17.38-.43.57-.65.19-.22.24-.38.38-.67.14-.29.07-.52-.05-.72-.12-.19-1.05-2.52-1.43-3.45-.38-.91-.76-.76-1.05-.76h-.9z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
const SquareMCPIcon = ({ size }: { size: number }) => (
|
||||||
|
<svg width={size} height={size} viewBox="0 0 64 64" fill="none">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="wg" x1="10" y1="10" x2="54" y2="54" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stopColor="#7DB6FF" />
|
||||||
|
<stop offset="1" stopColor="#0E63F6" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
d="M10 12C10 10.9 10.9 10 12 10H31V17H17V31H10V12ZM33 10H52C53.1 10 54 10.9 54 12V31H47V17H33V10ZM10 33H17V47H31V54H12C10.9 54 10 53.1 10 52V33ZM47 33H54V52C54 53.1 53.1 54 52 54H33V47H47V33Z"
|
||||||
|
fill="url(#wg)"
|
||||||
|
/>
|
||||||
|
<path d="M24 24H33V31H40V40H31V33H24V24Z" fill="#0E63F6" opacity="0.92" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const WhatsAppIntro = () => {
|
||||||
|
const frame = useCurrentFrame();
|
||||||
|
const { fps } = useVideoConfig();
|
||||||
|
|
||||||
|
const logoIn = spring({ fps, frame, config: SPRING_CFG });
|
||||||
|
const textIn = spring({ fps, frame: Math.max(0, frame - 20), config: SPRING_CFG });
|
||||||
|
const subIn = spring({ fps, frame: Math.max(0, frame - 40), config: SPRING_CFG });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AbsoluteFill style={{ alignItems: "center", justifyContent: "center", display: "flex", flexDirection: "column", gap: 32 }}>
|
||||||
|
{/* Logo pair */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 40,
|
||||||
|
opacity: logoIn,
|
||||||
|
transform: `scale(${0.7 + logoIn * 0.3})`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SquareMCPIcon size={120} />
|
||||||
|
<div style={{ fontFamily: FONT, color: "rgba(255,255,255,0.3)", fontSize: 64, fontWeight: 300 }}>×</div>
|
||||||
|
<WhatsAppIcon size={120} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Title */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontFamily: FONT,
|
||||||
|
color: "#ffffff",
|
||||||
|
fontSize: 64,
|
||||||
|
fontWeight: 800,
|
||||||
|
textAlign: "center",
|
||||||
|
lineHeight: 1.1,
|
||||||
|
opacity: textIn,
|
||||||
|
transform: `translateY(${(1 - textIn) * 40}px)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
SquareMCP × WhatsApp Business
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Subtitle */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontFamily: FONT,
|
||||||
|
color: "#25D366",
|
||||||
|
fontSize: 32,
|
||||||
|
fontWeight: 600,
|
||||||
|
opacity: subIn,
|
||||||
|
transform: `translateY(${(1 - subIn) * 24}px)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Sending messages via the Cloud API
|
||||||
|
</div>
|
||||||
|
</AbsoluteFill>
|
||||||
|
);
|
||||||
|
};
|
||||||
369
videos/remotion-demo/src/scenes/whatsapp/WhatsAppSplitScreen.tsx
Normal file
369
videos/remotion-demo/src/scenes/whatsapp/WhatsAppSplitScreen.tsx
Normal file
@@ -0,0 +1,369 @@
|
|||||||
|
import {
|
||||||
|
AbsoluteFill,
|
||||||
|
interpolate,
|
||||||
|
spring,
|
||||||
|
useCurrentFrame,
|
||||||
|
useVideoConfig,
|
||||||
|
} from "remotion";
|
||||||
|
import { FONT, SPRING_CFG, SPRING_SOFT } from "../../styles";
|
||||||
|
|
||||||
|
const WA_GREEN = "#25D366";
|
||||||
|
const WA_DARK = "#111b21";
|
||||||
|
const WA_BUBBLE = "#005c4b";
|
||||||
|
const WA_HEADER = "#202c33";
|
||||||
|
|
||||||
|
// ── Left panel: SquareMCP chat + API call ─────────────────────────────────────
|
||||||
|
|
||||||
|
const CURL_LINES = [
|
||||||
|
"curl -X POST \\",
|
||||||
|
" https://graph.facebook.com/v18.0/ \\",
|
||||||
|
" {PHONE_NUMBER_ID}/messages \\",
|
||||||
|
" -H 'Authorization: Bearer {TOKEN}' \\",
|
||||||
|
" -H 'Content-Type: application/json' \\",
|
||||||
|
" -d '{",
|
||||||
|
' "messaging_product": "whatsapp",',
|
||||||
|
' "to": "+19548716341",',
|
||||||
|
' "type": "text",',
|
||||||
|
' "text": { "body": "Hello from SquareMCP!" }',
|
||||||
|
" }'",
|
||||||
|
];
|
||||||
|
|
||||||
|
const RESPONSE_LINES = [
|
||||||
|
"{",
|
||||||
|
' "messaging_product": "whatsapp",',
|
||||||
|
' "messages": [{',
|
||||||
|
' "id": "wamid.HBgLMTk1NDg3MTYzNDEV..."',
|
||||||
|
" }]",
|
||||||
|
"}",
|
||||||
|
];
|
||||||
|
|
||||||
|
const LeftPanel = ({ frame, fps }: { frame: number; fps: number }) => {
|
||||||
|
const panelIn = spring({ fps, frame, config: SPRING_SOFT });
|
||||||
|
const chatIn = spring({ fps, frame: Math.max(0, frame - 10), config: SPRING_CFG });
|
||||||
|
const termIn = spring({ fps, frame: Math.max(0, frame - 30), config: SPRING_CFG });
|
||||||
|
|
||||||
|
// Animate curl lines appearing one by one
|
||||||
|
const curlProgress = interpolate(frame, [40, 140], [0, CURL_LINES.length], { extrapolateRight: "clamp" });
|
||||||
|
// Response appears after curl finishes
|
||||||
|
const responseProgress = interpolate(frame, [155, 210], [0, RESPONSE_LINES.length], { extrapolateRight: "clamp" });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
padding: "40px 32px 40px 48px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
gap: 24,
|
||||||
|
opacity: panelIn,
|
||||||
|
transform: `translateX(${(1 - panelIn) * -60}px)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Section label */}
|
||||||
|
<div style={{ fontFamily: FONT, color: "rgba(255,255,255,0.4)", fontSize: 20, fontWeight: 600, letterSpacing: 2, textTransform: "uppercase" }}>
|
||||||
|
SquareMCP — Sending message
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Chat prompt bubble */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
borderRadius: 20,
|
||||||
|
border: "1px solid rgba(14,99,246,0.35)",
|
||||||
|
background: "rgba(9,12,22,0.94)",
|
||||||
|
padding: "20px 24px",
|
||||||
|
opacity: chatIn,
|
||||||
|
transform: `translateY(${(1 - chatIn) * 30}px)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ fontFamily: FONT, color: "rgba(255,255,255,0.4)", fontSize: 16, marginBottom: 10 }}>Chat</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginLeft: "auto",
|
||||||
|
borderRadius: 18,
|
||||||
|
background: "linear-gradient(135deg, rgba(14,99,246,0.95), rgba(125,182,255,0.9))",
|
||||||
|
padding: "16px 20px",
|
||||||
|
color: "#08111f",
|
||||||
|
fontFamily: FONT,
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: 700,
|
||||||
|
lineHeight: 1.3,
|
||||||
|
maxWidth: "90%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Send a WhatsApp message to +1 954 871 6341:<br />
|
||||||
|
"Hello from SquareMCP!"
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Terminal */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
borderRadius: 16,
|
||||||
|
background: "#0d1117",
|
||||||
|
border: "1px solid rgba(37,211,102,0.2)",
|
||||||
|
padding: "18px 20px",
|
||||||
|
flex: 1,
|
||||||
|
opacity: termIn,
|
||||||
|
transform: `translateY(${(1 - termIn) * 30}px)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Terminal header */}
|
||||||
|
<div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 14 }}>
|
||||||
|
{["#ff5f57", "#febc2e", "#28c840"].map((c) => (
|
||||||
|
<div key={c} style={{ width: 12, height: 12, borderRadius: 999, background: c }} />
|
||||||
|
))}
|
||||||
|
<div style={{ marginLeft: 8, fontFamily: "ui-monospace, monospace", color: "rgba(255,255,255,0.3)", fontSize: 14 }}>
|
||||||
|
terminal — curl
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Prompt */}
|
||||||
|
<div style={{ fontFamily: "ui-monospace, monospace", color: "#7ee787", fontSize: 15, marginBottom: 6 }}>
|
||||||
|
$ {/* cursor blink when not yet started */}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Curl lines */}
|
||||||
|
{CURL_LINES.slice(0, Math.ceil(curlProgress)).map((line, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
style={{
|
||||||
|
fontFamily: "ui-monospace, monospace",
|
||||||
|
color: line.startsWith(" -d") || line.includes('"') ? "#79c0ff" : "#e6edf3",
|
||||||
|
fontSize: 15,
|
||||||
|
lineHeight: 1.6,
|
||||||
|
opacity: i < curlProgress - 1 ? 1 : curlProgress - i,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{line}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* Response */}
|
||||||
|
{responseProgress > 0 && (
|
||||||
|
<div style={{ marginTop: 12 }}>
|
||||||
|
<div style={{ fontFamily: "ui-monospace, monospace", color: WA_GREEN, fontSize: 14, marginBottom: 4 }}>
|
||||||
|
# Response (200 OK)
|
||||||
|
</div>
|
||||||
|
{RESPONSE_LINES.slice(0, Math.ceil(responseProgress)).map((line, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
style={{
|
||||||
|
fontFamily: "ui-monospace, monospace",
|
||||||
|
color: line.includes("wamid") ? WA_GREEN : "#e6edf3",
|
||||||
|
fontSize: 15,
|
||||||
|
lineHeight: 1.55,
|
||||||
|
opacity: i < responseProgress - 1 ? 1 : responseProgress - i,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{line}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ── Right panel: WhatsApp phone UI ────────────────────────────────────────────
|
||||||
|
|
||||||
|
const RightPanel = ({ frame, fps }: { frame: number; fps: number }) => {
|
||||||
|
const panelIn = spring({ fps, frame, config: SPRING_SOFT });
|
||||||
|
// Message bubble appears at frame 220 (after API response shown)
|
||||||
|
const msgIn = spring({ fps, frame: Math.max(0, frame - 220), config: SPRING_CFG });
|
||||||
|
const checkIn = spring({ fps, frame: Math.max(0, frame - 260), config: SPRING_CFG });
|
||||||
|
|
||||||
|
const showMsg = frame >= 220;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 440,
|
||||||
|
padding: "40px 48px 40px 24px",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
opacity: panelIn,
|
||||||
|
transform: `translateX(${(1 - panelIn) * 60}px)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Phone shell */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 340,
|
||||||
|
height: 680,
|
||||||
|
borderRadius: 44,
|
||||||
|
border: "8px solid #2a2a2a",
|
||||||
|
background: WA_DARK,
|
||||||
|
overflow: "hidden",
|
||||||
|
boxShadow: "0 40px 120px rgba(0,0,0,0.8), 0 0 0 1px rgba(255,255,255,0.06)",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Status bar */}
|
||||||
|
<div style={{ background: WA_HEADER, padding: "10px 20px 8px", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||||
|
<div style={{ fontFamily: FONT, color: "white", fontSize: 13, fontWeight: 600 }}>9:41</div>
|
||||||
|
<div style={{ display: "flex", gap: 6, alignItems: "center" }}>
|
||||||
|
{/* Signal bars */}
|
||||||
|
<div style={{ display: "flex", gap: 2, alignItems: "flex-end" }}>
|
||||||
|
{[8, 12, 16, 20].map((h, i) => (
|
||||||
|
<div key={i} style={{ width: 4, height: h, background: "white", borderRadius: 2, opacity: 0.9 }} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{/* Battery */}
|
||||||
|
<div style={{ width: 22, height: 11, border: "1.5px solid white", borderRadius: 3, padding: 1.5, display: "flex" }}>
|
||||||
|
<div style={{ flex: 1, background: WA_GREEN, borderRadius: 1 }} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Chat header */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: WA_HEADER,
|
||||||
|
borderBottom: "1px solid rgba(255,255,255,0.05)",
|
||||||
|
padding: "12px 16px",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 12,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ width: 40, height: 40, borderRadius: 999, background: WA_GREEN, display: "flex", alignItems: "center", justifyContent: "center" }}>
|
||||||
|
<div style={{ fontFamily: FONT, color: "white", fontSize: 18, fontWeight: 700 }}>S</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div style={{ fontFamily: FONT, color: "white", fontSize: 15, fontWeight: 600 }}>SquareMCP</div>
|
||||||
|
<div style={{ fontFamily: FONT, color: "rgba(255,255,255,0.45)", fontSize: 12 }}>Business Account</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Chat body */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
background: `url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23182229' fill-opacity='0.4'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`,
|
||||||
|
backgroundColor: "#0b141a",
|
||||||
|
padding: "16px 12px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Incoming message bubble */}
|
||||||
|
{showMsg && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
alignSelf: "flex-end",
|
||||||
|
maxWidth: "82%",
|
||||||
|
opacity: msgIn,
|
||||||
|
transform: `translateY(${(1 - msgIn) * 24}px) scale(${0.9 + msgIn * 0.1})`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: WA_BUBBLE,
|
||||||
|
borderRadius: "18px 4px 18px 18px",
|
||||||
|
padding: "10px 14px 22px",
|
||||||
|
position: "relative",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ fontFamily: FONT, color: "white", fontSize: 15, lineHeight: 1.45 }}>
|
||||||
|
Hello from SquareMCP!
|
||||||
|
</div>
|
||||||
|
{/* Timestamp + checks */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: 6,
|
||||||
|
right: 10,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 4,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ fontFamily: FONT, color: "rgba(255,255,255,0.5)", fontSize: 11 }}>9:41 AM</div>
|
||||||
|
{/* Double check marks */}
|
||||||
|
<div style={{ opacity: checkIn, display: "flex" }}>
|
||||||
|
<svg width="16" height="11" viewBox="0 0 16 11" fill="none">
|
||||||
|
<path d="M1 5.5L5 9.5L10 1" stroke={WA_GREEN} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
|
<path d="M6 5.5L10 9.5L15 1" stroke={WA_GREEN} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Input bar */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: WA_HEADER,
|
||||||
|
padding: "8px 12px",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 8,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
background: "#2a3942",
|
||||||
|
borderRadius: 24,
|
||||||
|
padding: "8px 16px",
|
||||||
|
fontFamily: FONT,
|
||||||
|
color: "rgba(255,255,255,0.3)",
|
||||||
|
fontSize: 14,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Message
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 38,
|
||||||
|
height: 38,
|
||||||
|
borderRadius: 999,
|
||||||
|
background: WA_GREEN,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="white">
|
||||||
|
<path d="M2 21l21-9L2 3v7l15 2-15 2v7z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ── Divider ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
const Divider = () => (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 1,
|
||||||
|
alignSelf: "stretch",
|
||||||
|
background: "linear-gradient(to bottom, transparent, rgba(37,211,102,0.25), transparent)",
|
||||||
|
margin: "40px 0",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
// ── Split screen scene ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export const WhatsAppSplitScreen = () => {
|
||||||
|
const frame = useCurrentFrame();
|
||||||
|
const { fps } = useVideoConfig();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AbsoluteFill style={{ display: "flex", flexDirection: "row", alignItems: "stretch" }}>
|
||||||
|
<LeftPanel frame={frame} fps={fps} />
|
||||||
|
<Divider />
|
||||||
|
<RightPanel frame={frame} fps={fps} />
|
||||||
|
</AbsoluteFill>
|
||||||
|
);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user