import React from "react"; import { AbsoluteFill, Sequence, interpolate, spring, useCurrentFrame, useVideoConfig, } from "remotion"; import { palette } from "./contract"; const FONT = "Archivo"; const CLAMP = { extrapolateLeft: "clamp", extrapolateRight: "clamp" } as const; const withAlpha = (hex: string, alpha: number): string => { const r = parseInt(hex.slice(1, 3), 16); const g = parseInt(hex.slice(3, 5), 16); const b = parseInt(hex.slice(5, 7), 16); return `rgba(${r}, ${g}, ${b}, ${alpha})`; }; const LogoMark: React.FC<{ size: number }> = ({ size }) => ( ); const PulseRings: React.FC<{ base: number; color: string }> = ({ base, color }) => { const frame = useCurrentFrame(); return ( <> {[0, 22].map((off) => { const t = (frame + off) % 44; const scale = interpolate(t, [0, 44], [0.8, 1.6]); const op = interpolate(t, [0, 32, 44], [0.4, 0.1, 0], CLAMP); return (
); })} ); }; const Intro: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const exitOp = interpolate(frame, [74, 89], [1, 0], CLAMP); const logoS = spring({ frame, fps, delay: 2, config: { damping: 13, stiffness: 170 } }); const logoScale = interpolate(logoS, [0, 1], [0.4, 1]); const logoOp = interpolate(logoS, [0, 0.4], [0, 1], CLAMP); const titleS = spring({ frame, fps, delay: 9, config: { damping: 16, stiffness: 120 } }); const titleY = interpolate(titleS, [0, 1], [48, 0]); const titleOp = interpolate(titleS, [0, 0.5], [0, 1], CLAMP); const subOp = interpolate(frame, [30, 46], [0, 1], CLAMP); const subY = interpolate(frame, [30, 48], [22, 0], CLAMP); const lineW = interpolate(frame, [38, 60], [0, 230], CLAMP); return (
Relay
Make room for focused work
); }; type CardSpec = { chip: number; color: string; lines: number[]; avatars: number; done: boolean; }; const DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri"]; const AV = [palette.accent, palette.secondary, palette.muted]; const PROGRESS = [0.72, 0.9, 0.55, 0.8, 0.64]; const BOARD: CardSpec[][] = [ [ { chip: 0.8, color: palette.secondary, lines: [0.85, 0.55], avatars: 2, done: true }, { chip: 0.6, color: palette.accent, lines: [0.7], avatars: 1, done: false }, { chip: 0.5, color: palette.muted, lines: [0.6], avatars: 1, done: false }, ], [ { chip: 0.7, color: palette.accent, lines: [0.8, 0.5], avatars: 2, done: true }, { chip: 0.55, color: palette.secondary, lines: [0.65], avatars: 2, done: false }, ], [ { chip: 0.9, color: palette.secondary, lines: [0.6], avatars: 3, done: false }, { chip: 0.5, color: palette.muted, lines: [0.75, 0.4], avatars: 1, done: true }, ], [ { chip: 0.65, color: palette.muted, lines: [0.8], avatars: 1, done: false }, { chip: 0.8, color: palette.secondary, lines: [0.55, 0.7], avatars: 2, done: true }, ], [ { chip: 0.75, color: palette.accent, lines: [0.7, 0.45], avatars: 2, done: false }, { chip: 0.5, color: palette.secondary, lines: [0.6], avatars: 1, done: true }, ], ]; const FEATURES = ["Plan together", "Protect focus time", "See progress"]; const BoardCard: React.FC<{ card: CardSpec; ci: number; ri: number; frame: number; fps: number }> = ({ card, ci, ri, frame, fps, }) => { const d = 8 + ci * 5 + ri * 7; const s = spring({ frame, fps, delay: d, config: { damping: 16, stiffness: 150 } }); const op = interpolate(s, [0, 0.5], [0, 1], CLAMP); const sc = interpolate(s, [0, 1], [0.7, 1]); const cd = 128 + ci * 4 + ri * 6; const cs = spring({ frame, fps, delay: cd, config: { damping: 12, stiffness: 220 } }); return (
{card.lines.map((w, li) => (
))}
{Array.from({ length: card.avatars }).map((_, ai) => { const avS = spring({ frame, fps, delay: d + 16 + ai * 4, config: { damping: 11, stiffness: 220 } }); const avOp = interpolate(avS, [0, 0.5], [0, 1], CLAMP); return (
); })}
{card.done ? (
) : null}
); }; const FocusBlock: React.FC<{ frame: number; fps: number }> = ({ frame, fps }) => { const op = interpolate(frame, [62, 74], [0, 1], CLAMP) * interpolate(frame, [112, 124], [1, 0], CLAMP); const s = spring({ frame, fps, delay: 62, config: { damping: 14, stiffness: 130 } }); const sc = interpolate(s, [0, 1], [0.92, 1]); const pulse = 1 + 0.018 * Math.sin(Math.max(0, frame - 74) / 5); const glow = 0.22 + 0.14 * Math.sin(Math.max(0, frame - 74) / 6); if (op <= 0) { return null; } return (
Focus time
); }; const ProductWindow: React.FC<{ frame: number; fps: number }> = ({ frame, fps }) => { const dim = interpolate(frame, [62, 74, 112, 124], [1, 0.4, 0.4, 1], CLAMP); const pct = Math.round(interpolate(frame, [126, 158], [0, 68], CLAMP)); const pillOp = interpolate(frame, [122, 132], [0, 1], CLAMP); const trackOp = interpolate(frame, [120, 130], [0, 1], CLAMP); return (
{[withAlpha(palette.muted, 0.5), palette.secondary, palette.accent].map((c, i) => (
))}
Team week
{`${pct}% this week`}
Relay
{[64, 52, 70, 44, 58].map((w, i) => (
))}
This week
{AV.map((c, i) => (
))}
{BOARD.map((cards, ci) => { const p = interpolate(frame, [126 + ci * 5, 152 + ci * 5], [0, PROGRESS[ci]], CLAMP); return (
{DAYS[ci]}
{cards.map((card, ri) => ( ))}
); })}
); }; const FeaturePanel: React.FC<{ frame: number }> = ({ frame }) => { return (
{FEATURES.map((title, i) => { const t = frame - i * 60; const inOp = interpolate(t, [0, 14], [0, 1], CLAMP); const outOp = i < 2 ? interpolate(t, [48, 60], [1, 0], CLAMP) : 1; const y = interpolate(t, [0, 14], [26, 0], CLAMP) + (i < 2 ? interpolate(t, [48, 60], [0, -18], CLAMP) : 0); const ulW = interpolate(t, [10, 28], [0, 76], CLAMP); return (
{`0${i + 1}`} / 03
{title}
); })}
{FEATURES.map((f, i) => { const end = i === 2 ? 1 : 0; const amt = interpolate( frame, [i * 60, i * 60 + 10, (i + 1) * 60, (i + 1) * 60 + 10], [0, 1, 1, end], CLAMP ); return (
); })}
); }; const ProductScene: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const enterOp = interpolate(frame, [0, 12], [0, 1], CLAMP); const exitOp = interpolate(frame, [166, 179], [1, 0], CLAMP); const winS = spring({ frame, fps, delay: 2, config: { damping: 18, stiffness: 90 } }); const winY = interpolate(winS, [0, 1], [56, 0]); return (
); }; const Outro: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const logoS = spring({ frame, fps, config: { damping: 13, stiffness: 160 } }); const logoScale = interpolate(logoS, [0, 1], [0.45, 1]); const logoOp = interpolate(logoS, [0, 0.4], [0, 1], CLAMP); const textS = spring({ frame, fps, delay: 6, config: { damping: 17, stiffness: 110 } }); const textY = interpolate(textS, [0, 1], [30, 0]); const textOp = interpolate(textS, [0, 0.55], [0, 1], CLAMP); const lineW = interpolate(frame, [16, 34], [0, 130], CLAMP); return (
Start your next week
with Relay
); }; export const BenchmarkVideo: React.FC = () => { return ( ); };