
3D Extruded Buildings & Urban Footprints
Real-world 3D building extrusions with dynamic sunlight shadows, terrain DEM elevations, and pitch/bearing camera controls.
3D perspective tilt workbench cards with dynamic mouse tracking, interactive token efficiency sliders, spring impulse testing, and dual-framework parity inspect.
Also available for Vue ->$pnpm dlx shadcn@latest add https://uipkge.dev/r/react/feature-hover-tilt-cards.json$npx shadcn@latest add https://uipkge.dev/r/react/feature-hover-tilt-cards.json$yarn dlx shadcn@latest add https://uipkge.dev/r/react/feature-hover-tilt-cards.json$bunx shadcn@latest add https://uipkge.dev/r/react/feature-hover-tilt-cards.jsonnpx shadcn@latest add @uipkge-react/feature-hover-tilt-cardsInstalls to:components/blocks/| Name | Type / Values | Default | Required |
|---|---|---|---|
className | string | — | optional |
'use client'
import * as React from 'react'
import { Cpu, Eye, Layers, LayoutGrid, Zap } from 'lucide-react'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { cn } from '@/lib/utils'
export interface FeatureHoverTiltCardsProps {
className?: string
}
export function FeatureHoverTiltCards({ className }: FeatureHoverTiltCardsProps) {
const [rotations, setRotations] = React.useState<Record<number, { rx: number; ry: number }>>({
0: { rx: 0, ry: 0 },
1: { rx: 0, ry: 0 },
2: { rx: 0, ry: 0 },
})
const [tokenScale, setTokenScale] = React.useState(100)
const [isPulsing, setIsPulsing] = React.useState(false)
const [activeMirror, setActiveMirror] = React.useState<'vue' | 'react'>('vue')
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>, index: number) => {
const card = e.currentTarget
const rect = card.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
const centerX = rect.width / 2
const centerY = rect.height / 2
const rotateX = ((y - centerY) / centerY) * -7
const rotateY = ((x - centerX) / centerX) * 7
setRotations((prev) => ({
...prev,
[index]: { rx: rotateX, ry: rotateY },
}))
}
const handleMouseLeave = (index: number) => {
setRotations((prev) => ({
...prev,
[index]: { rx: 0, ry: 0 },
}))
}
const triggerSpringTest = () => {
setIsPulsing(true)
setTimeout(() => setIsPulsing(false), 600)
}
return (
<section
data-slot="feature-hover-tilt-cards"
className={cn('bg-background relative overflow-hidden px-4 py-16 sm:px-6 sm:py-24 lg:px-8', className)}
>
<div className="mx-auto max-w-7xl space-y-12">
{/* Section Header */}
<div className="mx-auto max-w-3xl space-y-4 text-center">
<Badge variant="secondary" className="gap-1.5 px-3 py-1 font-mono text-xs shadow-xs">
<Eye className="text-primary size-3.5" />
Tactile Physics & Surface Depth
</Badge>
<h2 className="text-foreground text-3xl font-bold tracking-tight sm:text-4xl">
Engineered for tactile feedback & micro-interactions.
</h2>
<p className="text-muted-foreground text-base">
Hover over each workbench card to experience hardware-accelerated 3D depth and live interactive physics.
</p>
</div>
{/* 3D Perspective Tilt Cards Grid */}
<div className="grid grid-cols-1 gap-6 [perspective:1200px] lg:grid-cols-3">
{/* Card 1: Unbundled Token Inspector */}
<div
className="transition-transform duration-200 ease-out will-change-transform"
style={{
transform: `perspective(1000px) rotateX(${rotations[0].rx}deg) rotateY(${rotations[0].ry}deg)`,
}}
onMouseMove={(e) => handleMouseMove(e, 0)}
onMouseLeave={() => handleMouseLeave(0)}
>
<Card className="border-border bg-card/95 hover:border-primary/50 relative flex h-full flex-col justify-between space-y-6 overflow-hidden rounded-2xl p-6 text-left shadow-xl transition-[color,background-color,border-color,box-shadow] hover:shadow-sm">
<div className="space-y-3">
<div className="flex items-center justify-between">
<div className="bg-primary/10 text-primary flex size-9 items-center justify-center rounded-xl font-mono">
<Layers className="size-4" />
</div>
<Badge variant="outline" className="font-mono text-xs">
Zero Bloat
</Badge>
</div>
<h3 className="text-foreground font-mono text-lg font-bold">Unbundled Code Ownership</h3>
<p className="text-muted-foreground text-xs leading-relaxed">
AST-level code generation puts pristine component source directly in your repository.
</p>
{/* Interactive Token Scale Slider */}
<div className="border-border bg-muted/30 mt-4 space-y-2 rounded-xl border p-3.5">
<div className="flex items-center justify-between font-mono text-xs">
<span className="text-muted-foreground">Tree-Shake Efficiency:</span>
<span className="text-success font-bold">{tokenScale}%</span>
</div>
<input
type="range"
min="50"
max="100"
value={tokenScale}
onChange={(e) => setTokenScale(Number(e.target.value))}
className="accent-primary bg-border h-1.5 w-full cursor-pointer rounded-lg"
/>
<p className="text-muted-foreground font-mono text-xs">
Unused variants automatically pruned at compile time.
</p>
</div>
</div>
<div className="border-border/60 text-muted-foreground flex items-center justify-between border-t pt-4 font-mono text-xs">
<span>0 dependencies added</span>
<span className="text-primary font-semibold">✓ Pure Source</span>
</div>
</Card>
</div>
{/* Card 2: Spring Velocity Simulator */}
<div
className="transition-transform duration-200 ease-out will-change-transform"
style={{
transform: `perspective(1000px) rotateX(${rotations[1].rx}deg) rotateY(${rotations[1].ry}deg)`,
}}
onMouseMove={(e) => handleMouseMove(e, 1)}
onMouseLeave={() => handleMouseLeave(1)}
>
<Card className="border-border bg-card/95 hover:border-primary/50 relative flex h-full flex-col justify-between space-y-6 overflow-hidden rounded-2xl p-6 text-left shadow-xl transition-[color,background-color,border-color,box-shadow] hover:shadow-sm">
<div className="space-y-3">
<div className="flex items-center justify-between">
<div className="bg-warning/10 text-warning flex size-9 items-center justify-center rounded-xl font-mono">
<Zap className="size-4" />
</div>
<Badge variant="outline" className="border-warning/20 bg-warning/10 text-warning font-mono text-xs">
Fluid Motion
</Badge>
</div>
<h3 className="text-foreground font-mono text-lg font-bold">Spring Physics Engine</h3>
<p className="text-muted-foreground text-xs leading-relaxed">
Calibrated cubic-bezier curves for tactile, zero-overshoot micro-interactions.
</p>
{/* Interactive Spring Trigger Box */}
<div className="border-border bg-muted/30 mt-4 space-y-3 rounded-xl border p-3.5 text-center">
<div
className={cn(
'bg-primary text-primary-foreground mx-auto flex size-12 items-center justify-center rounded-2xl font-mono text-sm font-bold shadow-md transition-colors duration-300',
isPulsing ? 'bg-success ring-success/30 scale-125 rotate-12 ring-4' : 'scale-100',
)}
>
<Cpu className="size-5" />
</div>
<Button
size="sm"
variant="outline"
className="h-8 w-full font-mono text-xs"
onClick={triggerSpringTest}
>
Trigger Spring Impulse
</Button>
</div>
</div>
<div className="border-border/60 text-muted-foreground flex items-center justify-between border-t pt-4 font-mono text-xs">
<span>Duration: 180ms</span>
<span className="text-success font-semibold">✓ 60fps Native</span>
</div>
</Card>
</div>
{/* Card 3: Dual-Framework Mirror Comparator */}
<div
className="transition-transform duration-200 ease-out will-change-transform"
style={{
transform: `perspective(1000px) rotateX(${rotations[2].rx}deg) rotateY(${rotations[2].ry}deg)`,
}}
onMouseMove={(e) => handleMouseMove(e, 2)}
onMouseLeave={() => handleMouseLeave(2)}
>
<Card className="border-border bg-card/95 hover:border-primary/50 relative flex h-full flex-col justify-between space-y-6 overflow-hidden rounded-2xl p-6 text-left shadow-xl transition-[color,background-color,border-color,box-shadow] hover:shadow-sm">
<div className="space-y-3">
<div className="flex items-center justify-between">
<div className="bg-info/10 text-info flex size-9 items-center justify-center rounded-xl font-mono">
<LayoutGrid className="size-4" />
</div>
<Badge variant="outline" className="border-info/20 bg-info/10 text-info font-mono text-xs">
1:1 Parity
</Badge>
</div>
<h3 className="text-foreground font-mono text-lg font-bold">Dual-Framework Compiler</h3>
<p className="text-muted-foreground text-xs leading-relaxed">
Identical DOM attributes, variants, and keyboard ergonomics across Vue 3.5 & React 19.
</p>
{/* Interactive Framework Switcher */}
<div className="border-border bg-muted/30 mt-4 space-y-2 rounded-xl border p-3 font-mono text-xs">
<div className="bg-background border-border flex items-center gap-1 rounded-lg border p-1">
<button
type="button"
className={cn(
'flex-1 rounded py-1 text-center transition-colors',
activeMirror === 'vue'
? 'bg-primary text-primary-foreground font-semibold shadow-xs'
: 'text-muted-foreground',
)}
onClick={() => setActiveMirror('vue')}
>
Vue 3.5 SFC
</button>
<button
type="button"
className={cn(
'flex-1 rounded py-1 text-center transition-colors',
activeMirror === 'react'
? 'bg-primary text-primary-foreground font-semibold shadow-xs'
: 'text-muted-foreground',
)}
onClick={() => setActiveMirror('react')}
>
React 19 JSX
</button>
</div>
<p className="text-muted-foreground pt-1 text-xs">
{activeMirror === 'vue' ? '<script setup lang="ts"> + Reka UI' : "'use client' + Radix UI"}
</p>
</div>
</div>
<div className="border-border/60 text-muted-foreground flex items-center justify-between border-t pt-4 font-mono text-xs">
<span>AST Verified</span>
<span className="text-primary font-semibold">✓ 100% Match</span>
</div>
</Card>
</div>
</div>
</div>
</section>
)
}
export default FeatureHoverTiltCards
Raw manifest:https://uipkge.dev/r/react/feature-hover-tilt-cards.json