Skip to main content

Location Lower Third

location-lower-third.tsx
import React from 'react'; import {Easing, Interactive, interpolate, useCurrentFrame} from 'remotion'; const location = 'Berlin, Germany'; const venue = 'LocalFirstConf, July 14'; export const LocationLowerThird: React.FC = () => { const frame = useCurrentFrame(); const visibleLocationCharacters = Math.floor( interpolate( frame, [14, 38, 88, 108], [0, location.length, location.length, 0], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }, ), ); const visibleVenueCharacters = Math.floor( interpolate(frame, [27, 54, 82, 102], [0, venue.length, venue.length, 0], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }), ); return ( <Interactive.Div name="Container" style={{ position: 'relative', width: 680, height: 138, boxSizing: 'border-box', fontFamily: 'Arial, Helvetica, sans-serif', }} > <Interactive.Svg name="Location pin" viewBox="0 0 64 80" style={{ position: 'absolute', left: 56, top: 4, width: 104, height: 130, overflow: 'visible', filter: 'drop-shadow(0 6px 8px rgba(24, 24, 27, 0.14))', opacity: interpolate(frame, [0, 9, 108, 119], [0, 1, 1, 0], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }), translate: interpolate( frame, [0, 16, 106, 119], ['0px -10px', '0px 0px', '0px 0px', '0px -8px'], { easing: Easing.out(Easing.cubic), extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }, ), scale: interpolate(frame, [0, 16, 106, 119], [0.88, 1, 1, 0.92], { easing: Easing.out(Easing.cubic), extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }), transformOrigin: '52px 126px', }} > <path d="M32 3C15.4 3 4 15.4 4 31C4 50.8 22.1 69.6 29.3 76.2C30.8 77.6 33.2 77.6 34.7 76.2C41.9 69.6 60 50.8 60 31C60 15.4 48.6 3 32 3Z" pathLength="1" fill="#2563eb" fillOpacity={interpolate(frame, [5, 18, 105, 114], [0, 1, 1, 0], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', })} stroke="#1d4ed8" strokeDasharray="1" strokeDashoffset={interpolate( frame, [0, 16, 105, 116], [1, 0, 0, 1], { easing: Easing.out(Easing.cubic), extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }, )} strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" /> <circle cx="32" cy="30" r={interpolate(frame, [10, 21, 102, 112], [0, 9, 9, 0], { easing: Easing.out(Easing.cubic), extrapolateLeft: 'clamp', extrapolateRight: 'clamp', })} fill="#eff6ff" /> </Interactive.Svg> <div style={{ position: 'absolute', left: 184, top: 3, width: 440, height: 132, display: 'flex', flexDirection: 'column', }} > <div style={{ height: 82, display: 'flex', alignItems: 'center', overflow: 'hidden', }} > <Interactive.Div name="Location" dir="auto" style={{ minWidth: 0, maxWidth: 440, overflow: 'hidden', color: '#18181b', fontSize: 54, fontWeight: 700, letterSpacing: -1, lineHeight: 1, clipPath: `inset(0 ${ 100 - (visibleLocationCharacters / location.length) * 100 }% 0 0)`, textOverflow: 'ellipsis', whiteSpace: 'nowrap', opacity: interpolate(frame, [14, 22, 98, 110], [0, 1, 1, 0], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }), }} > {location} </Interactive.Div> </div> <div style={{ minHeight: 0, flex: 1, display: 'flex', alignItems: 'center', overflow: 'hidden', }} > <Interactive.Div name="Venue" dir="auto" style={{ minWidth: 0, maxWidth: 440, overflow: 'hidden', color: '#52525b', fontSize: 29, fontWeight: 500, lineHeight: 1, clipPath: `inset(0 ${ 100 - (visibleVenueCharacters / venue.length) * 100 }% 0 0)`, textOverflow: 'ellipsis', whiteSpace: 'nowrap', opacity: interpolate(frame, [27, 35, 92, 104], [0, 1, 1, 0], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }), }} > {venue} </Interactive.Div> </div> </div> </Interactive.Div> ); };