Web InnoventixFreeCode

Perspective Push Effect

Original · free

Image pushes back in perspective with an overlay on hover.

byWeb InnoventixReact + Tailwind
perspectivepushimageeffect
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-perspective-push.json
imgfx-perspective-push.tsx
"use client";

export default function ImgfxPerspectivePush() {
  return (
    <section className="relative w-full overflow-hidden bg-slate-50 px-6 py-24 dark:bg-slate-950 sm:px-10">
      <style>{`
        .ipp-stage {
          perspective: 1200px;
          perspective-origin: 50% 30%;
        }
        .ipp-card {
          transform-style: preserve-3d;
          transform: translateZ(0) rotateX(0deg) scale(1);
          transition: transform 0.65s cubic-bezier(0.2, 0.7, 0.2, 1),
            box-shadow 0.65s cubic-bezier(0.2, 0.7, 0.2, 1);
          will-change: transform;
        }
        .ipp-stage:hover .ipp-card,
        .ipp-stage:focus-within .ipp-card {
          transform: translateZ(-110px) rotateX(9deg) scale(0.955);
          box-shadow: 0 45px 80px -30px rgba(15, 23, 42, 0.55);
        }
        .ipp-img {
          transition: filter 0.65s cubic-bezier(0.2, 0.7, 0.2, 1),
            transform 0.65s cubic-bezier(0.2, 0.7, 0.2, 1);
          transform: scale(1.04);
        }
        .ipp-stage:hover .ipp-img,
        .ipp-stage:focus-within .ipp-img {
          filter: brightness(0.62) saturate(1.05);
          transform: scale(1);
        }
        .ipp-overlay {
          opacity: 0;
          transition: opacity 0.55s ease;
        }
        .ipp-stage:hover .ipp-overlay,
        .ipp-stage:focus-within .ipp-overlay {
          opacity: 1;
        }
        .ipp-caption {
          opacity: 0;
          transform: translateY(16px);
          transition: opacity 0.55s ease 0.05s, transform 0.55s cubic-bezier(0.2, 0.7, 0.2, 1) 0.05s;
        }
        .ipp-stage:hover .ipp-caption,
        .ipp-stage:focus-within .ipp-caption {
          opacity: 1;
          transform: translateY(0);
        }
        .ipp-frame:focus-visible {
          outline: 2px solid rgb(99 102 241);
          outline-offset: 4px;
        }
        @media (prefers-reduced-motion: reduce) {
          .ipp-card,
          .ipp-img {
            transition: filter 0.3s ease;
            transform: none !important;
          }
          .ipp-stage:hover .ipp-card,
          .ipp-stage:focus-within .ipp-card {
            transform: none !important;
            box-shadow: none;
          }
          .ipp-stage:hover .ipp-img,
          .ipp-stage:focus-within .ipp-img {
            transform: none !important;
          }
          .ipp-caption {
            transition: opacity 0.3s ease;
            transform: none !important;
          }
        }
      `}</style>

      <div className="mx-auto max-w-3xl">
        <div className="mb-10 text-center">
          <p className="text-xs font-semibold uppercase tracking-[0.25em] text-indigo-600 dark:text-indigo-400">
            Image Effect
          </p>
          <h2 className="mt-3 text-3xl font-semibold tracking-tight text-slate-900 dark:text-slate-50 sm:text-4xl">
            Perspective Push
          </h2>
          <p className="mt-3 text-sm text-slate-500 dark:text-slate-400">
            Hover to push the frame back in depth as the story surfaces.
          </p>
        </div>

        <div className="ipp-stage">
          <div
            className="ipp-frame ipp-card relative overflow-hidden rounded-2xl bg-slate-900 shadow-xl ring-1 ring-slate-900/10 dark:ring-white/10"
            tabIndex={0}
            role="group"
            aria-label="Coastal workshop, interactive perspective image"
          >
            <div className="relative aspect-[4/3] w-full">
              {/* eslint-disable-next-line @next/next/no-img-element */}
              <img
                src="/img/gallery/g14.webp"
                alt="Golden-hour light spilling across a quiet coastal workshop"
                loading="lazy"
                draggable={false}
                className="ipp-img h-full w-full object-cover"
              />

              <div className="ipp-overlay absolute inset-0 bg-gradient-to-t from-slate-950/85 via-slate-950/25 to-transparent" />

              <div className="ipp-caption absolute inset-x-0 bottom-0 p-6 sm:p-8">
                <p className="text-[0.7rem] font-semibold uppercase tracking-[0.22em] text-indigo-300">
                  Field Notes
                </p>
                <h3 className="mt-2 text-xl font-semibold text-white sm:text-2xl">
                  Golden Hour, Slow Craft
                </h3>
                <p className="mt-2 max-w-md text-sm leading-relaxed text-slate-200">
                  The room recedes and the light steps forward — a small depth
                  shift that lets the frame breathe before you read it.
                </p>
              </div>
            </div>
          </div>
        </div>

        <p className="mt-6 text-center text-xs text-slate-400 dark:text-slate-500">
          Tip: keyboard users can Tab to the frame to trigger the same effect.
        </p>
      </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 →