// terminal-typewriter — terminal typewriter trigger // A dark terminal window centered; "$ acme deploy --prod" is typed out character by character (2f/char, frame-deterministic // substring), with a block cursor blinking in a 12f square wave → rests 12f after typing → on the enter frame: the whole scene // pushes in over 6f with Easing.in(cubic), scale 1→3.2 driving toward the command line (blur added on the last 2f) hard-cutting to // FakeDashboard A full-screen, settling 1.06→1 over 4f. Ends with ≥40f of true stillness. import React from 'react'; import { useCurrentFrame, interpolate, Easing } from 'remotion'; import { G, FakeDashboard } from '../../_fixtures/Fixtures'; const CMD = 'acme deploy --prod'; // Timeline (30fps, 145f total) const T = { typeStart: 10, // starts typing typeEnd: 10 + CMD.length * 2, // 46: 18 chars × 2f enter: 58, // enter after a 12f rest pushEnd: 64, // 6f push ends, hard-cut frame settleEnd: 68, // dashboard settles 1.06→1 over 4f total: 145, // true stillness from f68, 77f }; // Terminal window geometry const TW = 1100; const TH = 620; const TL = (1920 - TW) / 2; // 410 const TT = (1080 - TH) / 2; // 230 const TITLEBAR = 52; const PAD = 34; // Command-line baseline (push-in focus): center of the second text line below the title bar const FOCUS_X = 960; const FOCUS_Y = TT + TITLEBAR + PAD + 92; // ≈ 408 const TerminalWindow: React.FC<{ chars: number; cursorOn: boolean }> = ({ chars, cursorOn }) => (
{/* Title bar: three-dot window controls (grayscale) */}
{['#6a6a68', '#8f8f8d', '#b5b5b3'].map((c, i) => (
))}
{/* Content area */}
{/* One line of history output as context */}
~/acme-app (main)
{'$ '} {CMD.substring(0, chars)}
); export const TerminalTypewriter: React.FC = () => { const frame = useCurrentFrame(); // Frame-deterministic typing: 2f/char const chars = Math.min(CMD.length, Math.max(0, Math.floor((frame - T.typeStart) / 2))); // Block cursor blinks in a 12f square wave throughout const cursorOn = frame % 12 < 6; // Enter push-in: whole scene scale 1→3.2 over 6f Easing.in(cubic), driving toward the command line const pushScale = interpolate(frame, [T.enter, T.pushEnd], [1, 3.2], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.in(Easing.cubic), }); // Motion blur on the last 2f (f62–f64); after the hard cut the veil is removed = conditional mount const pushBlur = interpolate(frame, [T.pushEnd - 2, T.pushEnd], [0, 10], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }); // Hard cut: from f64 the terminal scene unmounts entirely and the dashboard mounts const cut = frame >= T.pushEnd; // Dashboard settle: 1.06→1 over 4f const dashScale = interpolate(frame, [T.pushEnd, T.settleEnd], [1.06, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.out(Easing.cubic), }); return (
{!cut ? (
0 ? { filter: `blur(${pushBlur}px)` } : {}), }}>
) : (
)}
); };