import React from 'react'; import { AbsoluteFill, Img, interpolate, Sequence, spring, staticFile, useCurrentFrame, useVideoConfig, } from 'remotion'; import { colors, fonts } from '../lib/theme'; import { IPhone17ProFrame, SCREEN_W, SCREEN_H } from '../components/IPhone17ProFrame'; import { IOSKeyboard } from '../components/IOSKeyboard'; // ─── Scene timing (frames @ 30fps) ─── const TITLE_DUR = 60; const PHONES_DUR = 30; const TYPING_DUR = 610; const HOLD_DUR = 50; const OUTRO_DUR = 45; const TITLE_START = 0; const PHONES_START = TITLE_DUR; // 60 const TYPING_START = PHONES_START + PHONES_DUR; // 90 const HOLD_START = TYPING_START + TYPING_DUR; // 700 const OUTRO_START = HOLD_START + HOLD_DUR; // 750 export const ZEROLAG_TOTAL_FRAMES = OUTRO_START + OUTRO_DUR; // 795 // ─── iPhone 17 Pro safe area ─── const SAFE_AREA_TOP = 59; // Below Dynamic Island const PHONE_SCALE = 1.12; // Scale up to fill more of the frame // Claude Code header: tab bar + session info + prompt context from screenshot const HEADER_H = 120; // Terminal typing overlay: aligned with the ❯ prompt position in the Claude Code screenshot const TERMINAL_TOP = 185; const TERMINAL_LEFT = 14; const TERMINAL_FONT = 21; // Slightly smaller to fit toolbar below // Codeman toolbar from screenshot (bottom section showing /init, /clear, Run, etc.) const TOOLBAR_H = 95; // ─── Typing schedule ─── const CORRECT_TEXT = 'zerolag technology brings in a visual dom overlay to make typing instant, even if your codeman server is on the other side of the world'; const FRAME_GAP = 4; // ~133ms per keystroke (~75 WPM) // Remote connection lag: 600ms–2.7s per char (18–80 frames @ 30fps). // Periodic spikes simulate packet loss / retransmission bursts. // TCP head-of-line blocking causes a single spike to freeze all subsequent chars. const LAGGY_DELAYS = [ 24, 30, 26, 32, 72, 28, 22, 34, 26, 30, 20, 28, 36, 24, 30, 22, 26, 34, 28, 20, 68, 30, 24, 32, 26, 22, 28, 34, 30, 26, 32, 24, 80, 22, 30, 26, 28, 34, 24, 30, ]; type KeyAction = { frame: number; char: string; lagDelay: number }; const buildSchedule = (): KeyAction[] => { const actions: KeyAction[] = []; const lag = (i: number) => LAGGY_DELAYS[i % LAGGY_DELAYS.length]; for (let i = 0; i < CORRECT_TEXT.length; i++) { actions.push({ frame: i * FRAME_GAP, char: CORRECT_TEXT[i], lagDelay: lag(i) }); } return actions; }; const TYPING_SCHEDULE = buildSchedule(); /** * Replay actions in order up to current frame, computing the visible text buffer. * TCP-ordered: stops at first unresolved echo (head-of-line blocking). */ const computeVisibleText = (frame: number, withLag: boolean): string => { let buffer = ''; for (const a of TYPING_SCHEDULE) { const threshold = withLag ? a.frame + a.lagDelay : a.frame; if (frame < threshold) break; buffer += a.char; } return buffer; }; // ─── iOS Status Bar (sits in the safe area, flanking Dynamic Island) ─── const IOSStatusBar: React.FC = () => (
9:41
{/* Signal */} {/* WiFi */} {/* Battery */}
); // ─── Typing overlay ─── const TypingOverlay: React.FC<{ typed: string; cursorVisible: boolean; }> = ({ typed, cursorVisible }) => { const frame = useCurrentFrame(); const cursorOpacity = cursorVisible ? (Math.floor(frame / 18) % 2 === 0 ? 0.85 : 0.5) : 0; const lineH = Math.round(TERMINAL_FONT * 1.4); const charW = TERMINAL_FONT * 0.62; return (
{'❯ '} {typed}
); }; // ─── Single phone: iPhone 17 Pro + Claude Code header + typing + keyboard ─── const MobileCodeman: React.FC<{ typed: string; cursorVisible: boolean; activeKey?: string; pressAge?: number; showKeyboard?: boolean; noAnimation?: boolean; showPromo?: boolean; }> = ({ typed, cursorVisible, activeKey, pressAge, showKeyboard = true, noAnimation, showPromo }) => (
{/* iOS status bar in the safe area */} {/* Claude Code header from screenshot (tabs + session info) */}
{/* Fade to terminal background */}
{/* Dark mask: hides screenshot text below Claude Code info (e.g. "Try edit...") */}
{/* Smooth gradient blend from screenshot into dark terminal */}
{/* Typing animation */} {/* Codeman toolbar from screenshot (/init, /clear, /compact, Run, Run Shell, voice) */}
{/* Gradient blend at top */}
{/* Promo cards between text and toolbar (left phone only) */} {showPromo && } {/* iOS keyboard at bottom */} {showKeyboard && (
)}
); // ─── Label above phone (prominent header) ─── const PhoneLabel: React.FC<{ title: string; detail: string; dotColor: string; detailColor: string; }> = ({ title, detail, dotColor, detailColor }) => (
{title}
{detail}
); // ─── Promo banners (inside left phone, between text and keyboard) ─── const PromoBanners: React.FC = () => (
Codeman
github.com/Ark0N/Codeman
xterm-zerolag-input
npmjs.com/package/xterm-zerolag-input
); // ─── Title scene ─── const TitleScene: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const titleScale = spring({ frame, fps, config: { damping: 15, stiffness: 80 } }); const titleOpacity = interpolate(frame, [0, 20], [0, 1], { extrapolateRight: 'clamp' }); const subtitleOpacity = interpolate(frame, [15, 35], [0, 1], { extrapolateRight: 'clamp' }); return (
Zerolag Input
Local echo for remote terminal sessions
); }; // ─── Outro ─── const OutroScene: React.FC = () => { const frame = useCurrentFrame(); const opacity = interpolate(frame, [0, 20], [0, 1], { extrapolateRight: 'clamp' }); return (
Codeman
Zero-latency mobile input
npm i xterm-zerolag-input
); }; // ─── Typing demo scene ─── const TypingDemo: React.FC = () => { const frame = useCurrentFrame(); const laggyTyped = computeVisibleText(frame, true); const zerolagTyped = computeVisibleText(frame, false); let activeKey: string | undefined; let pressAge = 99; for (let i = TYPING_SCHEDULE.length - 1; i >= 0; i--) { const ev = TYPING_SCHEDULE[i]; if (frame >= ev.frame && frame < ev.frame + 5) { activeKey = ev.char; pressAge = frame - ev.frame; break; } } return (
); }; // ─── Phones entrance ─── const PanelsEntrance: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const scale = spring({ frame, fps, config: { damping: 15, stiffness: 80 } }); const opacity = interpolate(frame, [0, 10], [0, 1], { extrapolateRight: 'clamp' }); return (
); }; // ─── Main composition ─── export const ZerolagDemo: React.FC = () => { return ( ); };