import { interpolate } from 'remotion'; import { C } from '../lib/colors'; import { springIn, softSpring, clampLerp } from '../lib/easings'; // Phase 2 (frames 75–171 global → localFrame 0..96): build log streams in // line-by-line, then a server card emerges. // // Log lines stagger ~12 frames apart starting at localFrame 4. // Server card emerges at localFrame ~64. const LOG_LINES = [ { label: 'Generating spec', detail: '2 tools detected' }, { label: 'Static checks', detail: 'passed' }, { label: 'Building image', detail: '17.2s' }, { label: 'Deploying', detail: 'live' }, ]; const LINE_STAGGER = 10; const LINE_START = 4; const CARD_START = 60; export function BuildScene({ localFrame, fps }: { localFrame: number; fps: number }) { const panelIn = springIn(localFrame, fps, 0); const panelOpacity = clampLerp(localFrame, 0, 12); // Card emerges late in phase. const cardIn = softSpring(localFrame, fps, CARD_START, 24); // Once the card is up, the log panel slides up to make room. const panelShift = interpolate(cardIn, [0, 1], [0, -140]); return (
{/* Build log panel */}
{/* Panel header — tiny status row */}
build · notion-search ● running
{LOG_LINES.map((line, i) => ( ))}
{/* Server card (emerges in second half) */} {cardIn > 0.01 && ( )}
); } function LogLine({ label, detail, localFrame, startFrame, fps, }: { label: string; detail: string; localFrame: number; startFrame: number; fps: number; }) { const spring = springIn(localFrame, fps, startFrame); const opacity = clampLerp(localFrame, startFrame, startFrame + 10); const x = interpolate(spring, [0, 1], [-30, 0]); // Check fills in slightly after the line slides in. const checkFill = clampLerp(localFrame, startFrame + 6, startFrame + 14); return (
{/* Checkmark circle */}
{label} {detail}
); } function ServerCard({ progress, localFrame }: { progress: number; localFrame: number }) { const scale = interpolate(progress, [0, 1], [0.85, 1]); const y = interpolate(progress, [0, 1], [40, 180]); // Pulse the live dot at ~1Hz. const pulsePhase = (localFrame - 60) / 30; const livePulse = 0.6 + 0.4 * Math.sin(pulsePhase * Math.PI * 2); return (
{/* Header row: title + live dot */}
notion-search
live
{/* Tool rows */}
); } function ToolRow({ name, desc }: { name: string; desc: string }) { return (
{name} {desc}
); }