BrandFlow: A Smooth, Interactive Logo Showcase Inspired by Linear
Aug 31, 2025
BrandFlow is a sleek two-row logo grid with smooth hover effects and staggered transitions, inspired by Linear’s clean UI.
It is perfect for showcasing sponsors, clients, or partners on your website in an interactive way.
Key Features
- Two-row animated grid with smooth transitions.
- Blur and scale effect on hover for depth.
- Staggered logo entrance and exit animations.
- Interactive overlay button for calls to action.
- Minimal, modern, Linear-inspired design.
Code Example
/'use client'
import { CaretRightIcon } from '@phosphor-icons/react'
import { motion, AnimatePresence } from 'framer-motion'
import { useState, useEffect } from 'react'
const logos = [
[
['/crafts/logo1.svg', '/crafts/logo2.svg', '/crafts/logo3.svg'],
['/crafts/logo4.svg', '/crafts/logo5.svg', '/crafts/logo6.svg'],
],
[
['/crafts/logo7.svg', '/crafts/logo8.svg', '/crafts/logo9.svg'],
['/crafts/logo10.svg', '/crafts/logo11.svg', '/crafts/logo12.svg'],
],
]
const transition = { duration: 0.5, ease: 'easeInOut' }
const transition1 = { duration: 0.15, ease: 'easeInOut' }
const rowVariants = {
animate: { transition: { staggerChildren: 0.5 } },
exit: { transition: { staggerChildren: 0.5, staggerDirection: -1 } },
}
const logoVariants = {
enter: { opacity: 0, scale: 0.8, filter: 'blur(8px)' },
center: { opacity: 1, scale: 1, filter: 'blur(0px)', transition },
exit: { opacity: 0, scale: 1.1, filter: 'blur(8px)', transition },
}
const labelVariants = {
hidden: { opacity: 0, scale: 0.95 },
visible: { opacity: 1, scale: 1, transition: transition1 },
exit: { opacity: 0, scale: 0.95, transition: transition1 },
}
const Page = () => {
const [index, setIndex] = useState(0)
const [hovered, setHovered] = useState(false)
useEffect(() => {
const interval = setInterval(() => {
setIndex((prev) => (prev + 1) % logos.length)
}, 3000)
return () => clearInterval(interval)
}, [])
return (
<div className="max-w-3xl mx-auto min-h-screen w-screen flex flex-col items-center justify-center relative cursor-pointer">
<div className='flex flex-col -space-y-1 text-center tracking-tight text-xl text-white pb-15'>
<div>Powering the world's best product teams.</div>
<div className='text-neutral-400'>From next-gen startups to established enterprises.</div>
</div>
{/* Wrap both logos grid and overlay button in one hover container */}
<div
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
className="relative"
>
{/* Logos Grid with blur on hover */}
<motion.div
className="flex flex-col space-y-5 relative cursor-pointer pointer-events-auto"
style={{ filter: hovered ? 'blur(6px)' : 'blur(0px)' }}
transition={{ duration: 0.10, ease: 'easeInOut' }}
>
{logos[index].map((row, rowIndex) => (
<motion.div
key={rowIndex + '-' + index}
className="flex justify-center space-x-25"
variants={rowVariants}
initial="animate"
animate="animate"
exit="exit"
>
<AnimatePresence mode="wait">
{row.map((src, i) => (
<motion.img
key={src}
src={src}
className="w-24 h-24"
variants={logoVariants}
initial="enter"
animate="center"
exit="exit"
/>
))}
</AnimatePresence>
</motion.div>
))}
</motion.div>
{/* Overlay Label with motion */}
<AnimatePresence>
{hovered && (
<motion.div
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 pointer-events-auto"
variants={labelVariants}
initial="hidden"
animate="visible"
exit="exit"
>
<button className="flex items-center justify-center text-white font-medium bg-neutral-800 border border-neutral-600/60 text-sm px-3 py-1 rounded-full">
Meet our sponsors <CaretRightIcon size={14} className="text-neutral-400" />
</button>
</motion.div>
)}
</AnimatePresence>
</div>
<div className='pt-40'>
<a
href='/'
target="_blank"
rel="noopener noreferrer"
className='underline underline-offset-4 text-sm font-medium gap-1 text-[#f9a8d5] hover:text-[#facfe6] transition-colors duration-200 cursor-pointer'
>
Access the code on blog
</a>
</div>
</div>
)
}
export default Page