Showcase

Animations from past Functn projects, adapted for TaylorUI. Copy the components into your project and wire them up to your own data.


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:

  1. Copy src/ui/components/carousel/product-carousel.tsx into your app.
  2. Ensure TaylorUI carousel primitives are available (see file list below).
  3. Install embla-carousel-fade alongside embla-carousel-react.
  4. Replace placeholderProductList in @/assets with 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.tsx
  • src/ui/components/carousel/carousel.tsx
  • src/lib/cn.ts
  • src/animations/framer/variants.ts (for fadeUp)

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>
  );
}

Scroll-Animation

This Scroll-Animation is copied from the functndev/remus-webshop project and adapted to TaylorUI. See it live on the development test page at remus-exhausts.com.

A content panel sits alongside a two-column image gallery. As you scroll, Framer Motion's useScroll and useTransform drive opposing parallax on the left and right columns — the left column moves up while the right moves down, creating depth as the section passes through the viewport.

To reuse in your project:

  1. Copy src/animations/components/scroll-animation-gallery.tsx into your app.
  2. Ensure ButtonLink, cn, and PageWidth are available (see file list below).
  3. Edit PLACEHOLDER_IMAGES and PLACEHOLDER_CONTENT at the top of the copied file.
  4. Adjust parallaxOffset inside the component to control how far the columns travel.

Files to copy (skip any your project already has):

  • src/animations/components/scroll-animation-gallery.tsx
  • src/ui/structure/page-width/page-width.tsx
  • src/ui/components/button/button-link.tsx
  • src/lib/cn.ts
  • src/assets/index.ts (or provide your own ImageMedia images)

Dependencies: framer-motion, next, react, @remixicon/react

import { ScrollAnimationShowcase } from '@/animations/components/scroll-animation-gallery';
import { PageWidth } from '@/ui/structure/page-width/page-width';
 
// Renders with placeholder images and copy baked into the component.
export function CtaGallerySection() {
  return (
    <PageWidth width="wide">
      <ScrollAnimationShowcase />
    </PageWidth>
  );
}

To customise content, edit the constants at the top of scroll-animation-gallery.tsx:

import { type ImageMedia, placeholderImageList } from '@/assets';
 
const PLACEHOLDER_IMAGES = placeholderImageList.slice(0, 8);
 
const PLACEHOLDER_CONTENT = {
  title: 'Your title',
  subtitle: 'Your subtitle',
  supportingText: 'Your supporting text.',
  ctaLabel: 'Call to action',
  ctaHref: '/your-link',
};

Each image should match the ImageMedia type from @/assets (a next/image -compatible source with optional alt text). Use 8 images for the full two-column parallax effect — 4 per column on desktop.

Discover our gallery

Scroll to explore

Two image columns move in opposite directions as you scroll, creating a parallax effect alongside the content panel.

Learn more