Tilt (3D Hover)

Mouse-aware 3D perspective tilt. The tilt= attr activates the effect. CSS handles the transform; a tiny runtime script feeds --aura-tilt-x/y on mousemove. Respects prefers-reduced-motion.


Basic tilt

Hover the cards

Default tilt

tilt (8°)

Gentle tilt

tilt="5" (5°)

Strong tilt

tilt="lg" (15°)

<div tilt>…</div>           <!-- default: 8° -->
<div tilt="5">…</div>       <!-- 5° max -->
<div tilt="sm">…</div>      <!-- 5° preset -->
<div tilt="lg">…</div>      <!-- 15° preset -->
<div tilt="xl">…</div>      <!-- 25° preset (dramatic) -->

With shine overlay

tilt-shine — follows mouse position

Shine effect

Move mouse over me

Stronger tilt

tilt="10" + shine

<div tilt tilt-shine gradient="brand">…</div>
<div tilt="10" tilt-shine>…</div>

Scale on hover

tilt-scale — subtle grow effect

Tilt + scale

Grows 4% on hover

<div tilt tilt-scale>Grows slightly on hover</div>

CSS-only fallback

tilt-css — no JS, fixed angle on hover

CSS-only tilt

Pure CSS hover state

<!-- No JS, just a CSS :hover transform -->
<div tilt tilt-css style="--aura-tilt-max-deg:8deg">…</div>

How it works

The CSS sets a 3D perspective transform reading two CSS custom properties. The runtime listens to mousemove and writes those vars per-frame:

/* CSS side (tilt.css) */
[tilt] {
  transform: perspective(800px)
    rotateX(var(--aura-tilt-x, 0deg))
    rotateY(var(--aura-tilt-y, 0deg));
}

/* Runtime feeds the vars on mousemove */
el.style.setProperty('--aura-tilt-x', `${rotX}deg`)
el.style.setProperty('--aura-tilt-y', `${rotY}deg`)

/* Tokens */
--aura-tilt-perspective: 800px
--aura-tilt-duration:    150ms