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 */}
{/* Tool rows */}
);
}
function ToolRow({ name, desc }: { name: string; desc: string }) {
return (
);
}