Web InnoventixFreeCode

Scanlines Effect

Original · free

CRT scanlines overlay that intensifies on hover.

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

import { useRef } from "react";
import { motion, useInView, useReducedMotion } from "motion/react";

export default function ImgfxScanlines() {
  const reduceMotion = useReducedMotion();
  const rootRef = useRef<HTMLDivElement>(null);
  const inView = useInView(rootRef, { once: true, margin: "-15% 0px" });

  return (
    <section className="relative w-full overflow-hidden bg-neutral-100 px-6 py-20 text-neutral-900 sm:px-10 sm:py-28 dark:bg-neutral-950 dark:text-neutral-50">
      <style>{`
        @keyframes crtscan_sweep {
          0%   { transform: translateY(-120%); }
          100% { transform: translateY(120%); }
        }
        @keyframes crtscan_flicker {
          0%, 100% { opacity: 0.92; }
          48%      { opacity: 0.86; }
          49%      { opacity: 1;    }
          51%      { opacity: 0.9;  }
          80%      { opacity: 0.96; }
        }
        .crtscan_lines {
          background-image: repeating-linear-gradient(
            to bottom,
            rgba(0, 0, 0, 0)   0px,
            rgba(0, 0, 0, 0)   2px,
            rgba(0, 0, 0, 0.16) 3px,
            rgba(0, 0, 0, 0.16) 4px
          );
          background-size: 100% 4px;
          opacity: 0.55;
          transition: opacity 450ms ease, background-size 450ms ease;
        }
        .crtscan_frame:hover .crtscan_lines,
        .crtscan_frame:focus-within .crtscan_lines {
          opacity: 1;
          background-size: 100% 3px;
        }
        .crtscan_sweep {
          background: linear-gradient(
            to bottom,
            rgba(255, 255, 255, 0) 0%,
            rgba(255, 255, 255, 0.14) 45%,
            rgba(255, 255, 255, 0.28) 50%,
            rgba(255, 255, 255, 0.14) 55%,
            rgba(255, 255, 255, 0) 100%
          );
          height: 40%;
          opacity: 0;
          transition: opacity 450ms ease;
          animation: crtscan_sweep 3.6s linear infinite;
        }
        .crtscan_frame:hover .crtscan_sweep,
        .crtscan_frame:focus-within .crtscan_sweep {
          opacity: 1;
        }
        .crtscan_flicker {
          transition: filter 450ms ease;
        }
        .crtscan_frame:hover .crtscan_flicker,
        .crtscan_frame:focus-within .crtscan_flicker {
          animation: crtscan_flicker 0.5s steps(2, end) infinite;
          filter: saturate(1.15) contrast(1.06);
        }
        @media (prefers-reduced-motion: reduce) {
          .crtscan_sweep { animation: none; }
          .crtscan_frame:hover .crtscan_flicker,
          .crtscan_frame:focus-within .crtscan_flicker { animation: none; }
        }
      `}</style>

      <motion.div
        ref={rootRef}
        initial={reduceMotion ? false : { opacity: 0, y: 28 }}
        animate={inView && !reduceMotion ? { opacity: 1, y: 0 } : undefined}
        transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
        className="mx-auto max-w-2xl"
      >
        <div className="mb-8 text-center">
          <span className="inline-block rounded-full border border-emerald-500/40 bg-emerald-500/10 px-3 py-1 text-xs font-semibold uppercase tracking-[0.2em] text-emerald-700 dark:text-emerald-300">
            CRT Scanlines
          </span>
          <h2 className="mt-4 text-3xl font-bold tracking-tight sm:text-4xl">
            Broadcast, on an old tube
          </h2>
        </div>

        <div
          tabIndex={0}
          className="crtscan_frame group relative aspect-[4/5] w-full cursor-pointer overflow-hidden rounded-2xl bg-black shadow-xl shadow-neutral-900/20 ring-1 ring-neutral-900/10 outline-none focus-visible:ring-2 focus-visible:ring-emerald-500 dark:shadow-black/40 dark:ring-white/10"
        >
          {/* eslint-disable-next-line @next/next/no-img-element */}
          <img
            src="/img/gallery/g14.webp"
            alt="Portrait styled as a vintage cathode-ray television broadcast"
            loading="lazy"
            draggable={false}
            className="crtscan_flicker h-full w-full scale-105 object-cover transition-transform duration-700 ease-out group-hover:scale-100"
          />

          {/* curvature + vignette */}
          <div
            aria-hidden="true"
            className="pointer-events-none absolute inset-0"
            style={{
              boxShadow:
                "inset 0 0 60px 12px rgba(0,0,0,0.55), inset 0 0 8px 2px rgba(120,255,200,0.06)",
            }}
          />

          {/* scanlines */}
          <div
            aria-hidden="true"
            className="crtscan_lines pointer-events-none absolute inset-0"
          />

          {/* moving sweep beam */}
          <div
            aria-hidden="true"
            className="crtscan_sweep pointer-events-none absolute inset-x-0 top-0 will-change-transform"
          />

          {/* subtle RGB fringe tint */}
          <div
            aria-hidden="true"
            className="pointer-events-none absolute inset-0 mix-blend-screen opacity-30"
            style={{
              background:
                "linear-gradient(115deg, rgba(255,0,80,0.10), rgba(0,255,180,0) 35%, rgba(0,120,255,0.10))",
            }}
          />

          <div className="pointer-events-none absolute left-4 top-4 flex items-center gap-2 font-mono text-[10px] uppercase tracking-widest text-emerald-300/90">
            <span className="h-2 w-2 animate-pulse rounded-full bg-rose-500" />
            REC 00:14
          </div>
        </div>

        <p className="mt-5 text-center text-sm text-neutral-500 dark:text-neutral-400">
          Hover or focus the frame — the scanlines tighten and the beam sweeps.
        </p>
      </motion.div>
    </section>
  );
}

Dependencies

motion

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 →