Image Ticker

v1.0.0
FreeGalleryInteractiveReduced Motion

A gorgeous, cinematic dual-ticker displaying rows of images rotating in opposite directions with built-in lightbox functionality.

Image Ticker

Installation

npx vectorvesper add image-ticker

Run npx vectorvesper init once first to set up your project.

Dependencies

npm install framer-motion
  • framer-motion

Usage

Import

import ImageTicker from "@/components/vv/image-ticker/ImageTicker";

Usage

<ImageTicker />

Client-only component — disable SSR

This component requires browser APIs and must be rendered client-side only.

import dynamic from "next/dynamic";

const ImageTicker = dynamic(
  () => import("@/components/vv/image-ticker/ImageTicker"),
  { ssr: false }
);
This component respects prefers-reduced-motion and provides a graceful fallback.

Props

A premium dual-strip infinite image ticker with perspective rotations, micro-interactions, and a built-in lightbox viewer. Hovering pauses the scroll; clicking cards launches a luxurious animated overlay with ambient backglow. Includes ImageTicker, SmoothTicker, and LightboxOverlay.

<ImageTicker />

The main overlay layout wrapping two rotated infinite tickers and a title overlay.

PropTypeDefaultDescription
topImages*string[]Array of image URLs for the top ticker strip.
bottomImages*string[]Array of image URLs for the bottom ticker strip.
topRotationnumber35Skew/rotation angle in degrees for the top ticker.
bottomRotationnumber-35Skew/rotation angle in degrees for the bottom ticker.
backgroundColorstring"#030303"Fallback background color of the container.
heightstring"100vh"CSS height string of the parent viewport wrapper.
titlestringBig overlay text displayed center-stage on top of the strips.
titlePosition"left" | "right" | "center""right"Alignment of the overlay title.
showAmbientGlowbooleantrueEnables a colored radial glow orb in the background.
showNoiseGrainbooleantrueEnables an organic film-grain overlay animation.
showVignettebooleantrueEnables dark vignette gradients on the viewport edges.
enableLightboxbooleantrueEnables the fullscreen LightboxOverlay on card clicks.
titleFontFamilystring"'Bebas Neue', sans-serif"Font family of the overlay title.
titleFontSizestring"clamp(2rem, 4vw, 6rem)"CSS font size of the overlay title.
titleColorstring"rgba(255, 255, 255, 0.95)"Text color of the overlay title.
titleOffsetstring"8vw"Horizontal margin/offset spacing for left/right title alignments.
ambientGlowColorstring"rgba(127,140,255,0.06)"Color of the background ambient glow orb.
onImageClick(src: string) => voidCallback fired when an image card is clicked.
classNamestringExtra CSS class names for the outer wrapper container.
tickerPropsPartial<SmoothTickerProps>{}Configuration overrides forwarded to both ticker strips.
lightboxPropsPartial<LightboxOverlayProps>{}Configuration overrides forwarded to the lightbox component.

<SmoothTicker />

A standalone horizontal infinite scroll strip with custom card animations (sweep shine, hover lift).

PropTypeDefaultDescription
images*string[]Array of image URLs to tile.
direction1 | -11Scroll direction: 1 (left-to-right) or -1 (right-to-left).
cardWidthnumber170Width of individual cards in px.
cardHeightnumber200Height of individual cards in px.
gapnumber20Gap spacing between cards in px.
speednumber0.05Scrolling speed multiplier.
pauseOnHoverbooleantruePauses ticker scrolling when hovering anywhere inside the strip.
showHoverGlowbooleantrueAdds a subtle border glow to the hovered card.
showShineSweepbooleantrueTriggers a metallic diagonal shine sweep when mouse enters a card.
showGradientBorderbooleantrueDisplays a high-end glassmorphic border gradient on the cards.
onCardClick(src: string) => voidCallback fired when a card in the strip is clicked.
cardBorderRadiusnumber14Corner radius of individual image cards in px.
containerBorderRadiusnumber30Corner radius of the strip container frame in px.
containerHeightnumber230Height of the strip container in px.
containerBackgroundstring"#060608"Background color of the strip container track.
cardBackgroundstring"#0a0a0e"Background fallback color of individual image cards.
classNamestringExtra CSS class names for the strip container.

<LightboxOverlay />

A react-dom portal-rendered lightbox modal with spring entrance, backdrop blur, close hint, and ambient backglow.

PropTypeDefaultDescription
src*string | nullThe image URL to display. Modal opens when truthy, closes when null.
onClose*() => voidCallback fired when the backdrop, close button, or ESC key is clicked.
imageWidthstring"420px"Width of the active image frame (CSS length).
imageHeightstring"540px"Height of the active image frame (CSS length).
backdropBlurstring"24px"CSS backdrop-filter blur amount for the overlay.
showAmbientGlowbooleantruePaints a colorful ambient shadow halo matching the image's edges.
borderRadiusstring"24px"Border radius of the active image frame (CSS length).
overlayColorstring"rgba(3,3,3,0.8)"Background color of the fullscreen backdrop overlay.
closeHintTextstring"Click anywhere to close"Instructional hint text shown below the image.
showCloseHintbooleantrueShow or hide the close instruction hint text.
classNamestringExtra CSS classes applied to the portal container.

Examples

Double-strip rotated marquee
const pics = ["/img1.jpg", "/img2.jpg", "/img3.jpg", "/img4.jpg"];

<ImageTicker
  topImages={pics}
  bottomImages={pics}
  title="PORTFOLIO"
/>
Standalone horizontal stripClean, flat ticker strip scrolling right-to-left.
<SmoothTicker
  images={["/1.jpg", "/2.jpg", "/3.jpg"]}
  direction={-1}
  speed={0.08}
  cardWidth={200}
  cardHeight={250}
/>
Client component suite. Relies on Framer Motion's useAnimationFrame and React Portals for lightbox overlays.
Automatically stops auto-scrolling animations and bypasses entry spring transitions if the system preference for reduced motion is active.

Source

"use client";
import { motion } from "framer-motion";
import { useState } from "react";
import LightboxOverlay from "./LightboxOverlay";
import SmoothTicker from "./SmoothTicker";

import type { LightboxOverlayProps } from "./LightboxOverlay";
import type { SmoothTickerProps } from "./SmoothTicker";

export type ImageTickerProps = {
  topImages: string[];
  bottomImages: string[];
  topRotation?: number;
  bottomRotation?: number;
  backgroundColor?: string;
  height?: string;
  title?: string;
  titleFontFamily?: string;
  titleFontSize?: string;
  titleColor?: string;
  titlePosition?: "left" | "right" | "center";
  titleOffset?: string;
  showAmbientGlow?: boolean;
  ambientGlowColor?: string;
  showNoiseGrain?: boolean;
  showVignette?: boolean;
  enableLightbox?: boolean;
  onImageClick?: (src: string) => void;
  tickerProps?: Partial<
    Omit<SmoothTickerProps, "images" | "direction" | "onCardClick">
  >;
  lightboxProps?: Partial<Omit<LightboxOverlayProps, "src" | "onClose">>;
  className?: string;
};

const ImageTicker = ({
  topImages,
  bottomImages,
  topRotation = 35,
  bottomRotation = -35,
  backgroundColor = "#030303",
  height = "100vh",
  title,
  titleFontFamily = "'Bebas Neue', sans-serif",
  titleFontSize = "clamp(2rem, 4vw, 6rem)",
  titleColor = "rgba(255, 255, 255, 0.95)",
  titlePosition = "right",
  titleOffset = "8vw",
  showAmbientGlow = true,
  ambientGlowColor = "rgba(127,140,255,0.06)",
View on GitHub →Report an issue