Lens Reveal Hero
A mysterious hero section where content is revealed by a flashlight-like lens following the cursor.
Installation
Add this component to your project using the CLI:
npx vui-registry-cli-v1 add lens-reveal-heroSource Code
"use client"
import React, { useRef, useState } from "react"
import { motion, useMotionValue, useSpring } from "framer-motion"
import { Search } from "lucide-react"
export default function LensRevealHero() {
const containerRef = useRef<HTMLDivElement>(null)
const [hovered, setHovered] = useState(false)
const x = useMotionValue(0)
const y = useMotionValue(0)
// Smooth spring physics for the lens movement
const springX = useSpring(x, { stiffness: 150, damping: 15, mass: 0.1 })
const springY = useSpring(y, { stiffness: 150, damping: 15, mass: 0.1 })
function onMouseMove(e: React.MouseEvent<HTMLDivElement>) {
const rect = containerRef.current?.getBoundingClientRect()
if (!rect) return
x.set(e.clientX - rect.left)
y.set(e.clientY - rect.top)
setHovered(true)
}
function onMouseLeave() {
setHovered(false)
}
return (
<div
ref={containerRef}
className="relative w-full h-[600px] overflow-hidden bg-neutral-950 cursor-none group rounded-2xl shadow-2xl border border-neutral-800"
onMouseMove={onMouseMove}
onMouseLeave={onMouseLeave}
>
{/* Base Layer: Monochrome / Blurred */}
<div className="absolute inset-0 z-0">
<img
src="https://images.unsplash.com/photo-1492144534655-ae79c964c9d7?q=80&w=1966&auto=format&fit=crop"
alt="Supercar"
className="w-full h-full object-cover filter grayscale blur-[2px] brightness-[0.4] scale-105"
/>
<div className="absolute inset-0 bg-neutral-950/50" />
{/* Text Content Base */}
<div className="absolute inset-0 flex flex-col items-center justify-center text-center z-10 pointer-events-none p-4">
<h1 className="text-6xl md:text-9xl font-black text-white/10 tracking-tighter uppercase select-none transition-colors duration-700">
VELOCITY
</h1>
<p className="mt-6 text-white/20 font-mono tracking-[0.5em] text-sm md:text-base uppercase select-none">
Experience the speed
</p>
</div>
</div>
{/* Reveal Layer: Full Color / Sharp */}
<motion.div
className="absolute inset-0 z-20 pointer-events-none"
style={{
maskImage: 'radial-gradient(circle 200px at var(--x) var(--y), black 0%, transparent 100%)',
WebkitMaskImage: 'radial-gradient(circle 200px at var(--x) var(--y), black 0%, transparent 100%)',
// @ts-ignore
'--x': springX,
// @ts-ignore
'--y': springY,
}}
>
<img
src="https://images.unsplash.com/photo-1492144534655-ae79c964c9d7?q=80&w=1966&auto=format&fit=crop"
alt="Supercar"
className="w-full h-full object-cover scale-105"
/>
<div className="absolute inset-0 bg-gradient-to-t from-neutral-900/40 to-transparent mix-blend-overlay" />
{/* Text Content Reveal */}
<div className="absolute inset-0 flex flex-col items-center justify-center text-center z-10">
<h1 className="text-6xl md:text-9xl font-black text-white tracking-tighter uppercase drop-shadow-[0_0_30px_rgba(255,255,255,0.3)] select-none">
VELOCITY
</h1>
<p className="mt-6 text-white font-mono tracking-[0.5em] text-sm md:text-base uppercase select-none drop-shadow-md">
Experience the speed
</p>
</div>
</motion.div>
{/* Custom Cursor Lens UI */}
<motion.div
className="absolute top-0 left-0 w-[400px] h-[400px] rounded-full z-30 pointer-events-none flex items-center justify-center"
style={{
x: springX,
y: springY,
translateX: '-50%',
translateY: '-50%',
opacity: hovered ? 1 : 0,
scale: hovered ? 1 : 0.5
}}
>
{/* Glass Ring */}
<div className="absolute inset-0 rounded-full border border-white/20 bg-white/5 backdrop-blur-[2px] shadow-[0_0_40px_rgba(255,255,255,0.1)]" />
{/* Inner Ring */}
<div className="absolute inset-[20px] rounded-full border border-white/10" />
{/* Decorative Marks */}
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-[2px] h-6 bg-white/50" />
<div className="absolute bottom-0 left-1/2 -translate-x-1/2 w-[2px] h-6 bg-white/50" />
<div className="absolute left-0 top-1/2 -translate-y-1/2 w-6 h-[2px] bg-white/50" />
<div className="absolute right-0 top-1/2 -translate-y-1/2 w-6 h-[2px] bg-white/50" />
{/* Center Crosshair */}
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
<Search className="w-8 h-8 text-white/50" strokeWidth={1} />
</div>
</motion.div>
</div>
)
}
Dependencies
framer-motion: latestclsx: latesttailwind-merge: latest
Props
Component property reference.
| Name | Type | Default | Description |
|---|---|---|---|
| title | string | 'VELOCITY' | Main heading text. |
| subtitle | string | 'Experience the speed' | Subheading text. |
| imageUrl | string | undefined | Background image URL. |
| lensSize | number | 200 | Radius of the reveal lens in pixels. |
Most components here are inspired by outstanding libraries and creators in the ecosystem. I don’t claim to be the original author — this is my space for learning, rebuilding, and understanding great work at a deeper level.
I’m still a student of the craft, constantly studying the best and translating what I learn through my own perspective. Every piece reflects curiosity, respect for the community, and small creative touches that feel true to me.
I’ve done my best to credit inspirations properly. If anything is missing or inaccurate, I truly appreciate a message so it can be corrected with care.

