Docs

Shape Shifter

A hero section with a shape-shifting component in the center

requires interactionhover

Installation

Update tailwind.config.js

theme: {
    extend: {
     keyframes: {
        "shape-shift": {
          "0%": {
            width: "40px",
            height: "20px",
          },
     }
    },
  },

Run the following command

It will create a new file called shape-shifter.tsx inside the components/animata/hero directory.

mkdir -p components/animata/hero && touch components/animata/hero/shape-shifter.tsx

Paste the code

Open the newly created file and paste the following code:

import Marquee from "@/animata/container/marquee";
import { cn } from "@/lib/utils";
 
const images: { src: string; alt: string; className?: string }[] = [
  {
    src: "https://images.unsplash.com/photo-1465804575741-338df8554e02?q=80&w=600&auto=format&fit=crop&ixlib=rb-4.0.3",
    alt: "Image 1",
  },
  {
    src: "https://images.unsplash.com/photo-1495985812444-236d6a87bdd9?w=600&auto=format&fit=crop&q=60&ixlib=rb-4.0.3",
    alt: "Image 3",
  },
  {
    src: "https://images.unsplash.com/photo-1451976426598-a7593bd6d0b2?q=80&w=600&auto=format&fit=crop&ixlib=rb-4.0.3",
    alt: "Image 2",
  },
  {
    src: "https://images.unsplash.com/photo-1479839672679-a46483c0e7c8?q=80&w=600&auto=format&fit=crop&ixlib=rb-4.0.3",
    alt: "Image 4",
  },
  {
    src: "https://images.unsplash.com/photo-1611816055460-618287c870bd?q=80&w=600&auto=format&fit=crop&ixlib=rb-4.0.3",
    alt: "Image 5",
  },
];
 
const placeholderChildren = (
  /* Marquee is optional and can be replaced with a different component like video. */
  <Marquee className="absolute inset-0 [--gap:2px]" applyMask={false} pauseOnHover>
    {images.map((image, index) => (
      /* Use `next/image` and remove the line below. */
      /* eslint-disable-next-line @next/next/no-img-element */
      <img key={`image_${index}`} {...image} alt={image.alt ?? ""} />
    ))}
  </Marquee>
);
 
export default function ShapeShifter({
  prefix = "Shape",
  suffix = "Shifter",
  className,
  containerClassName,
  children,
}: {
  className?: string;
  containerClassName?: string;
  children?: React.ReactNode;
  prefix?: React.ReactNode;
  suffix?: React.ReactNode;
}) {
  return (
    <div
      className={cn(
        "text-md group flex min-h-96 w-full min-w-fit flex-col items-center justify-center gap-3 font-bold text-foreground transition-all sm:flex-row sm:text-xl",
        containerClassName,
      )}
    >
      <div>{prefix}</div>
      <div
        className={cn(
          "relative animate-[shape-shift] overflow-hidden bg-black p-0 transition-all ease-in-out direction-alternate repeat-infinite group-hover:[animation-play-state:paused] dark:bg-white",
          className,
        )}
        // Magic number based on length of images.
        style={{ animationDuration: "8s" }}
      >
        {children ?? placeholderChildren}
      </div>
      <div>{suffix}</div>
    </div>
  );
}

Credits

Inspired by Good Loop

Images by Unsplash