Showcase
Animations from past Functn projects, adapted for TaylorUI. Copy the components into your project and wire them up to your own data.
MotionRevealIndividual below wraps each top-level section in its own
MotionReveal, so every section reveals independently as it scrolls into
view — no shared trigger or stagger, unlike MotionRevealGroup. See
Motion reveal for the full rundown.
Product carousel
This Product carousel is copied from the functndev/wsk-bank-relaunch project and adapted to TaylorUI. See it live in the Unsere Produkte section on wsk-bank.at.
The carousel combines TaylorUI carousel primitives with embla-carousel-fade so
slides crossfade in place. A fixed text region above animates title and
description on slide change (fadeUp from @/animations). The thumbnail rail
below expands the active item and accepts clicks to jump between slides.
To reuse in your project:
- Copy
src/ui/components/carousel/product-carousel.tsxinto your app. - Ensure TaylorUI carousel primitives are available (see file list below).
- Install
embla-carousel-fadealongsideembla-carousel-react. - Replace
placeholderProductListin@/assetswith your own slide data — each slide needs a title, description, optional links, and an image.
Files to copy (skip any your project already has):
src/ui/components/carousel/product-carousel.tsxsrc/ui/components/carousel/carousel.tsxsrc/lib/cn.tssrc/animations/framer/variants.ts(forfadeUp)
Dependencies: embla-carousel-react, embla-carousel-fade, framer-motion,
next, react
import { ProductCarouselShowcase } from '@/ui/components/carousel/product-carousel';
// Renders with placeholder slides from @/assets.
export function ProductsSection() {
return (
<section>
<ProductCarouselShowcase />
</section>
);
}To customise slide content, map your data to the ProductSlide type from
@/assets:
import type { ProductSlide } from '@/assets';
const products: ProductSlide[] = items.map((item) => ({
productTitle: item.title,
productText: item.description,
productLinks: item.links,
image: item.image,
}));Animated Buttons
Uses Framer Motion's layoutId inside a LayoutGroup to smoothly morph between two
buttons with different positions and sizes as you scroll. The button starts small
at the top-left and grows into a large variant at the bottom-right once the
container reaches the viewport center — scrolling back reverses the animation.
Wrap both button positions in LayoutGroup, give each motion.div the same
layoutId, and use useScroll to toggle between them. AnimatePresence keeps
the exiting button alive so the morph is seamless.
import {
AnimatePresence,
LayoutGroup,
motion,
useMotionValueEvent,
useScroll,
} from 'framer-motion';
function AnimatedButton() {
const ref = useRef(null);
const { scrollYProgress } = useScroll({
target: ref,
offset: ['start end', 'center center'],
});
const [showFirst, setShowFirst] = useState(true);
useMotionValueEvent(scrollYProgress, 'change', (v) => setShowFirst(v < 0.8));
return (
<LayoutGroup>
<div ref={ref} className="relative h-[50vh]">
<AnimatePresence initial={false}>
{showFirst ? (
<motion.div
key="first"
layoutId="my-button"
className="absolute top-8 left-8"
>
<Button size="small">Small</Button>
</motion.div>
) : (
<motion.div
key="second"
layoutId="my-button"
className="absolute right-8 bottom-8"
>
<Button size="large">Large</Button>
</motion.div>
)}
</AnimatePresence>
</div>
</LayoutGroup>
);
}