import React from 'react'; import { AbsoluteFill, interpolate, Sequence, spring, useCurrentFrame, useVideoConfig, } from 'remotion'; import { palette } from './contract'; const fontFamily = 'Archivo, sans-serif'; const bg = palette.background; const fg = palette.foreground; const accent = palette.accent; const secondary = palette.secondary; const muted = palette.muted; const CLAMP = { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', } as const; const rgba = (hex: string, alpha: number): string => { const h = hex.replace('#', ''); const r = parseInt(h.slice(0, 2), 16); const g = parseInt(h.slice(2, 4), 16); const b = parseInt(h.slice(4, 6), 16); return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + alpha + ')'; }; const delayedSpring = ( frame: number, fps: number, delay: number, config: { damping?: number; stiffness?: number; mass?: number } = {} ): number => { return spring({ frame: Math.max(0, frame - delay), fps, config: { damping: 200, ...config }, }); }; const Backdrop: React.FC = () => ( ); const Intro: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const enter = delayedSpring(frame, fps, 0, { damping: 26, stiffness: 110 }); const scale = interpolate(enter, [0, 1], [0.92, 1]); const titleOpacity = interpolate(frame, [0, 12], [0, 1], CLAMP); const subOpacity = interpolate(frame, [26, 44], [0, 1], CLAMP); const subRise = interpolate( delayedSpring(frame, fps, 26, { damping: 24 }), [0, 1], [24, 0] ); const exit = interpolate(frame, [76, 89], [1, 0], CLAMP); const bars = [accent, secondary, fg]; return (
{bars.map((c, i) => { const p = delayedSpring(frame, fps, 4 + i * 6, { damping: 18, stiffness: 130, }); return (
); })}
Relay
Make room for focused work
); }; const FeatureScene: React.FC<{ index: string; kicker: string; title: string; panelTitle: string; children: React.ReactNode; }> = ({ index, kicker, title, panelTitle, children }) => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const enter = delayedSpring(frame, fps, 0, { damping: 26 }); const exit = interpolate(frame, [50, 59], [1, 0], CLAMP); const textRise = interpolate(enter, [0, 1], [36, 0]); const panelSlide = interpolate(enter, [0, 1], [56, 0]); return (
{index}
{kicker}
{title}
{[muted, secondary, accent].map((c, i) => (
))}
{panelTitle}
{children}
); }; const Board: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const cols = [ { name: 'Backlog', x: 0 }, { name: 'This week', x: 300 }, { name: 'Done', x: 600 }, ]; const cards = [ { label: 'Design review', tag: 'Product', initials: 'AK', from: 0, to: 1, delay: 10, avatar: secondary, row: 0, }, { label: 'Sprint planning', tag: 'Ops', initials: 'JM', from: 0, to: 1, delay: 20, avatar: accent, row: 1, }, { label: 'Launch checklist', tag: 'Growth', initials: 'RS', from: 1, to: 2, delay: 34, avatar: secondary, row: 2, }, ]; const highlight = delayedSpring(frame, fps, 10, { damping: 22 }); return (
{cols.map((c) => (
{c.name}
))} {cards.map((card, i) => { const move = delayedSpring(frame, fps, card.delay, { damping: 28, stiffness: 120, }); const x = interpolate( move, [0, 1], [cols[card.from].x, cols[card.to].x] ); const enterP = delayedSpring(frame, fps, 4 + i * 4, { damping: 26 }); return (
{card.label}
{card.tag}
{card.initials}
); })}
); }; const Schedule: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const enter = delayedSpring(frame, fps, 2, { damping: 26 }); const focusP = delayedSpring(frame, fps, 10, { damping: 24, stiffness: 90, }); const focusH = interpolate(focusP, [0, 1], [30, 336]); const meetings = [ { label: 'Standup', time: '9:00 - 9:30', top: 20, height: 64, dismissAt: 999 }, { label: '1:1 with Sam', time: '10:00 - 11:00', top: 120, height: 120, dismissAt: 16, }, { label: 'Team sync', time: '1:00 - 2:00', top: 336, height: 120, dismissAt: 24, }, ]; const hours = [ { label: '9 AM', top: 20 }, { label: '10', top: 104 }, { label: '11', top: 188 }, { label: '12', top: 272 }, { label: '1 PM', top: 356 }, ]; return (
{hours.map((h) => (
{h.label}
))}
{meetings.map((m) => { const d = m.dismissAt > 100 ? 0 : delayedSpring(frame, fps, m.dismissAt, { damping: 26 }); return (
{m.label}
{m.time}
); })}
Deep work
Protected
10:00 AM - 1:00 PM - Focus time
); }; const Progress: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const values = [0.42, 0.58, 0.5, 0.72, 0.64, 0.86, 1]; const days = ['M', 'T', 'W', 'T', 'F', 'S', 'S']; const chartH = 330; const numberP = delayedSpring(frame, fps, 14, { damping: 30 }); const value = interpolate(numberP, [0, 1], [0, 18.5]); return (
Focus hours - this week
{value.toFixed(1)}h
{values.map((v, i) => { const p = delayedSpring(frame, fps, 6 + i * 5, { damping: 20, stiffness: 120, }); const h = v * chartH * p; const last = i === values.length - 1; return (
); })}
{days.map((d, i) => (
{d}
))}
); }; const Outro: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const enter = delayedSpring(frame, fps, 0, { damping: 26 }); const subOpacity = interpolate(frame, [22, 34], [0, 1], CLAMP); const underline = delayedSpring(frame, fps, 10, { damping: 24 }); return (
Relay
Start your next week
with Relay
Plan together · Protect focus time · See progress
); }; export const BenchmarkVideo: React.FC = () => { return ( ); };