Hover Text
A premium editorial layout with glassmorphic hover cards that track the cursor and reveal contextual content. Features tight spring physics, side-aware positioning, and a collector-edition aesthetic.
Installation
Add this component to your project using the CLI:
npx vui-registry-cli-v1 add hover-textSource Code
'use client'
import React, { useState, useCallback } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
/**
* @component ViratKohliEditorial_Premium_Full
* @version 6.0.0
* @description Full-content editorial with glassmorphic cards, border-text heading, and tight cursor tracking.
*/
const PREVIEW_DATA = {
perfect_stroke: {
image: 'https://images.unsplash.com/photo-1531415074968-036ba1b575da?q=80&w=800&auto=format&fit=crop',
title: 'THE PERFECT STROKE',
subtitle: 'A masterclass in timing and the art of the cover drive.',
side: 'right'
},
t20_glory: {
image: 'https://images.unsplash.com/photo-1624194697120-34347cff8b58?q=80&w=1217&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
title: 'T20 GLORY',
subtitle: 'The iconic moment of lifting the trophy under the floodlights.',
side: 'right'
},
victory_roar: {
image: 'https://images.unsplash.com/photo-1624194770831-00d655f9a1e4?q=80&w=1170&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
title: 'VICTORY ROAR',
subtitle: 'Pure emotion captured in the heat of a championship win.',
side: 'right'
},
peak_performance: {
image: 'https://images.unsplash.com/photo-1552435053-01c010307582?q=80&w=1256&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
title: 'PEAK PERFORMANCE',
subtitle: 'Redefining the standard of fitness in modern sport.',
side: 'right'
},
tactical_genius: {
image: 'https://images.unsplash.com/photo-1540747913346-19e32dc3e97e?q=80&w=1305&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
title: 'TACTICAL GENIUS',
subtitle: 'Leading the team with strategic brilliance and aggression.',
side: 'left'
},
test_mastery: {
image: 'https://images.unsplash.com/photo-1644984785609-676ed703333e?q=80&w=1170&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
title: 'TEST MASTERY',
subtitle: 'Dominating the red ball format with unmatched technique.',
side: 'left'
},
red_ball_legend: {
image: 'https://images.unsplash.com/photo-1531415074968-036ba1b575da?q=80&w=1167&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
title: 'RED BALL LEGEND',
subtitle: 'A legacy written in the toughest conditions across the globe.',
side: 'left'
},
global_phenomenon: {
image: 'https://images.unsplash.com/photo-1561501900-3701fa6a0864?q=80&w=800&auto=format&fit=crop',
title: 'GLOBAL PHENOMENON',
subtitle: 'The visual definition of a sport loved by billions.',
side: 'left'
}
}
const styles = `
.vk-root {
min-height: 100%;
width: 100%;
background-color: transparent;
color: #1a1a1a;
padding: 60px 24px;
font-family: 'Times New Roman', serif;
position: relative;
overflow-x: hidden;
}
.vk-root::before {
content: "";
position: absolute;
inset: 0;
opacity: 0.03;
pointer-events: none;
background-image: url("https://www.transparenttextures.com/patterns/stardust.png");
}
.vk-container {
max-width: 1200px;
margin: 0 auto;
position: relative;
z-index: 10;
}
.vk-header {
text-align: center;
margin-bottom: 4rem;
}
/* PREMIUM BORDER TEXT HEADING */
.vk-header h1 {
font-size: clamp(3rem, 12vw, 8rem);
font-weight: 900;
line-height: 0.8;
letter-spacing: -0.04em;
margin: 0;
text-transform: uppercase;
color: transparent;
-webkit-text-stroke: 1.5px #111;
}
.vk-grid {
display: grid;
grid-template-columns: 1fr 1px 1fr;
gap: 4rem;
}
.vk-divider {
background-color: rgba(0,0,0,0.1);
height: 100%;
}
.vk-column {
font-family: 'Inter', sans-serif;
font-size: 1rem;
line-height: 1.8;
text-align: justify;
color: #333;
}
.vk-link {
font-weight: 700;
color: #b51a1a;
cursor: pointer;
text-decoration: underline;
text-underline-offset: 4px;
text-decoration-color: rgba(181, 26, 26, 0.2);
transition: all 0.3s ease;
}
.vk-link:hover {
color: #ef4444;
text-decoration-color: #ef4444;
}
.vk-card {
position: absolute;
pointer-events: none;
z-index: 100;
}
/* GLASSMORPHIC DESIGN */
.vk-inner-card {
background: rgba(255, 255, 255, 0.35);
backdrop-filter: blur(15px) saturate(160%);
-webkit-backdrop-filter: blur(15px) saturate(160%);
border: 1px solid rgba(255, 255, 255, 0.4);
border-radius: 12px;
padding: 12px;
width: 300px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.15);
}
.vk-inner-card img {
width: 100%;
height: 220px;
object-fit: cover;
border-radius: 8px;
margin-bottom: 12px;
}
.vk-card-title {
font-family: 'Inter', sans-serif;
font-weight: 900;
font-size: 0.8rem;
letter-spacing: 0.1em;
text-transform: uppercase;
margin-bottom: 4px;
}
.vk-card-sub {
font-family: 'Inter', sans-serif;
font-size: 0.7rem;
color: #444;
line-height: 1.4;
}
.vk-footer {
margin-top: 80px;
display: flex;
flex-direction: column;
align-items: center;
border-top: 1px solid #eee;
padding-top: 40px;
}
.vk-sig {
width: 240px;
opacity: 0.8;
mix-blend-mode: multiply;
}
.section-mark {
font-family: 'Inter', sans-serif;
font-size: 0.65rem;
font-weight: 800;
letter-spacing: 0.4em;
text-transform: uppercase;
color: #999;
display: block;
margin-bottom: 2rem;
}
@media (max-width: 900px) {
.vk-grid { grid-template-columns: 1fr; }
.vk-divider { display: none; }
}
`
interface HoverTextProps {
className?: string
initialMoment?: keyof typeof PREVIEW_DATA | null
}
const HoverText = ({ className, initialMoment = null }: HoverTextProps) => {
const [active, setActive] = useState<keyof typeof PREVIEW_DATA | null>(initialMoment)
const [mousePos, setMousePos] = useState({ x: 0, y: 0 })
const handleMouseMove = useCallback((e: React.MouseEvent) => {
setMousePos({ x: e.clientX, y: e.clientY })
}, [])
return (
<div className={`vk-root ${className || ''}`} onMouseMove={handleMouseMove}>
<style dangerouslySetInnerHTML={{ __html: styles }} />
<div className="vk-container">
<header className="vk-header">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1 }}
>
<span className="section-mark">A Tribute to the Gentleman's Game</span>
<h1>The Art of Cricket</h1>
</motion.div>
</header>
<div className="vk-grid">
{/* LEFT COLUMN */}
<div className="vk-column">
<p>
The narrative of <strong>The Art of Cricket</strong> is one of unprecedented intensity. What began as a
pastoral pastime evolved into <span className="vk-link" onMouseEnter={() => setActive('perfect_stroke')} onMouseLeave={() => setActive(null)}>The Perfect Stroke</span>.
Its history is a testament to the fact that greatness is not given; it is taken through
relentless obsession and a refusal to settle for mediocrity. Every boundary scored was a
statement of intent, a psychological victory over the opposition.
</p>
<p style={{ marginTop: '2rem' }}>
In the high-octane world of franchise cricket, the journey is defined by passion.
The world watches in awe as the <span className="vk-link" onMouseEnter={() => setActive('t20_glory')} onMouseLeave={() => setActive(null)}>T20 Glory </span>
finally becomes a reality, sparking a celebration that transcends the sport itself.
The sheer raw energy of the <span className="vk-link" onMouseEnter={() => setActive('victory_roar')} onMouseLeave={() => setActive(null)}>Victory Roar </span>
remains etched in the memories of millions who stand by their teams through seasons of grit,
heartbreak, and eventual redemption.
</p>
<p style={{ marginTop: '2rem' }}>
Beyond the runs and the trophies, the greatest contribution remains the cultural shift
towards <span className="vk-link" onMouseEnter={() => setActive('peak_performance')} onMouseLeave={() => setActive(null)}>Peak Performance</span>.
Athletes transform themselves into high-performance machines,
forcing the world to rethink the importance of physical discipline in sport.
Influence ensures that fitness becomes a non-negotiable standard for the next generation.
</p>
</div>
<div className="vk-divider" />
{/* RIGHT COLUMN */}
<div className="vk-column">
<p>
While white-ball cricket provides the spectacle, the red-ball format reveals the soul.
<span className="vk-link" onMouseEnter={() => setActive('tactical_genius')} onMouseLeave={() => setActive(null)}>Tactical Genius </span>
will be remembered for its unapologetic aggression. Captains don't just want to win; they want to
dominate, especially on foreign soil where others had previously faltered, instilling a
fearless belief in the squad.
</p>
<p style={{ marginTop: '2rem' }}>
Standing tall as the <span className="vk-link" onMouseEnter={() => setActive('test_mastery')} onMouseLeave={() => setActive(null)}>Test Mastery</span>,
bringing a passion to the five-day game that helps keep the format alive in a T20 era.
Statistically and spiritually, the <span className="vk-link" onMouseEnter={() => setActive('red_ball_legend')} onMouseLeave={() => setActive(null)}>Red Ball Legend</span>
represents a warrior who thrives when the conditions are most hostile, the
crowds most vocal, and the stakes at their absolute highest.
</p>
<p style={{ marginTop: '2rem' }}>
As we look back at the <span className="vk-link" onMouseEnter={() => setActive('global_phenomenon')} onMouseLeave={() => setActive(null)}>Global Phenomenon</span>,
it becomes clear that cricket is never just a game—it is a movement. The signature is
not just on the scorecards, but on the very heart of the game itself, ensuring that
its legacy will be spoken with reverence for decades to come.
</p>
</div>
</div>
<footer className="vk-footer">
<motion.img
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
transition={{ delay: 0.5, duration: 1 }}
src="https://images.unsplash.com/photo-1565787113569-be8aa6f5da41?q=80&w=765&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Signature"
className="vk-sig"
/>
<p style={{ fontFamily: 'Inter', fontSize: '0.7rem', color: '#aaa', marginTop: '20px', letterSpacing: '3px' }}>
MANUSCRIPT NO. 01 // THE SPIRIT OF CRICKET
</p>
</footer>
</div>
<AnimatePresence>
{active && (
<motion.div
key={active}
className="vk-card"
initial={{ opacity: 0, scale: 0.95 }}
animate={{
opacity: 1,
scale: 1,
left: mousePos.x,
top: mousePos.y
}}
exit={{ opacity: 0, scale: 0.95 }}
// FAST SPRING PHYSICS: Glues card to cursor
transition={{ type: "spring", stiffness: 700, damping: 40, mass: 0.3 }}
style={{
x: PREVIEW_DATA[active].side === 'right' ? 30 : -370,
y: -150
}}
>
<div className="vk-inner-card">
<img src={PREVIEW_DATA[active].image} alt="Kohli Moment" />
<div className="vk-card-title">{PREVIEW_DATA[active].title}</div>
<div className="vk-card-sub">{PREVIEW_DATA[active].subtitle}</div>
</div>
</motion.div>
)}
</AnimatePresence>
</div>
)
}
export default HoverText;
Dependencies
framer-motion: latest
Props
Component property reference.
| Name | Type | Default | Description |
|---|---|---|---|
| initialMoment | "legend" | "ipl_glory" | "ipl_roar" | "fitness" | "captain" | "test_purist" | "greatest_player" | "ipl_winner" | null | null | Optional key from PREVIEW_DATA to keep a specific moment active when the page mounts. |
| className | string | undefined | Optional wrapper className to adjust spacing, background, or layout when embedding the editorial surface. |
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.

