Web InnoventixFreeCode

Hue Rotate Effect

Original · free

Image hue-shifts through colours on hover.

byWeb InnoventixReact + Tailwind
huerotateimageeffect
Open

Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.

npx shadcn@latest add https://webinnoventix.com/r/imgfx-hue-rotate.json
imgfx-hue-rotate.tsx
"use client";

import { useState } from "react";

const IMAGES = [
  { src: "/img/gallery/g07.webp", alt: "Sunlit modern building facade with layered geometry" },
  { src: "/img/gallery/g18.webp", alt: "Calm coastline at golden hour with soft waves" },
  { src: "/img/gallery/g24.webp", alt: "Dense forest canopy seen from below" },
] as const;

export default function ImgfxHueRotate() {
  const [active, setActive] = useState<number | null>(null);

  return (
    <section className="relative w-full overflow-hidden bg-neutral-50 px-6 py-20 text-neutral-900 dark:bg-neutral-950 dark:text-neutral-100 sm:px-10 sm:py-28">
      <style>{`
        @keyframes huefx_spin {
          from { filter: saturate(1.4) hue-rotate(0deg); }
          to   { filter: saturate(1.4) hue-rotate(360deg); }
        }
        .huefx-img {
          filter: saturate(1) hue-rotate(0deg);
          transition: filter 600ms cubic-bezier(0.22, 1, 0.36, 1), transform 600ms cubic-bezier(0.22, 1, 0.36, 1);
          will-change: filter, transform;
        }
        .huefx-card:hover .huefx-img,
        .huefx-card:focus-visible .huefx-img {
          animation: huefx_spin 6s linear infinite;
          transform: scale(1.05);
        }
        @media (prefers-reduced-motion: reduce) {
          .huefx-card:hover .huefx-img,
          .huefx-card:focus-visible .huefx-img {
            animation: none;
            filter: saturate(1.4) hue-rotate(140deg);
            transform: none;
          }
          .huefx-img { transition: filter 300ms ease; }
        }
      `}</style>

      <div className="mx-auto max-w-5xl">
        <header className="mb-14 text-center">
          <p className="mb-3 text-xs font-semibold uppercase tracking-[0.28em] text-violet-600 dark:text-violet-400">
            Image Effect
          </p>
          <h2 className="text-3xl font-semibold tracking-tight sm:text-4xl">
            Hue Rotate
          </h2>
          <p className="mx-auto mt-4 max-w-md text-sm text-neutral-600 dark:text-neutral-400">
            The same photograph, cycling endlessly through the spectrum. Hover any frame to set its colours in motion.
          </p>
        </header>

        <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
          {IMAGES.map((img, i) => (
            <button
              key={img.src}
              type="button"
              onMouseEnter={() => setActive(i)}
              onMouseLeave={() => setActive(null)}
              onFocus={() => setActive(i)}
              onBlur={() => setActive(null)}
              aria-label={`${img.alt} — hover to rotate hue`}
              className="huefx-card group relative block aspect-[4/5] overflow-hidden rounded-2xl bg-neutral-200 shadow-sm ring-1 ring-neutral-900/5 outline-none transition-shadow duration-500 focus-visible:ring-2 focus-visible:ring-violet-500 hover:shadow-xl dark:bg-neutral-800 dark:ring-white/10"
            >
              {/* eslint-disable-next-line @next/next/no-img-element */}
              <img
                src={img.src}
                alt={img.alt}
                loading="lazy"
                draggable={false}
                className="huefx-img absolute inset-0 h-full w-full object-cover"
              />

              <span
                aria-hidden="true"
                className="pointer-events-none absolute inset-0 bg-gradient-to-t from-black/50 via-transparent to-transparent"
              />

              <span
                aria-hidden="true"
                className="pointer-events-none absolute bottom-3 left-3 flex items-center gap-1.5 rounded-full bg-white/85 px-3 py-1 text-[11px] font-medium text-neutral-700 opacity-0 backdrop-blur transition-opacity duration-300 group-hover:opacity-100 group-focus-visible:opacity-100 dark:bg-black/60 dark:text-neutral-200"
              >
                <span
                  className={`inline-block h-2 w-2 rounded-full ${
                    active === i ? "bg-emerald-500" : "bg-neutral-400"
                  }`}
                />
                {active === i ? "cycling" : "hover to reveal"}
              </span>
            </button>
          ))}
        </div>
      </div>
    </section>
  );
}

Dependencies

None (React + Tailwind only).

Licence

Built by Web Innoventix. Free for personal and commercial use, no attribution required.

Built by Web Innoventix

Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.

Get a free quote

Similar components

Browse all →