Components / Motion / Tilt Card
Tilt Card beta
A card that tips toward the cursor in 3D, with a glare that follows and a layer that floats.
Northwind Pro
The whole workspace, one payment. This card is the part — tip it.
<div style="display:flex;justify-content:center;padding:10px 0">
<div class="k-tilt" data-tilt>
<div class="k-tilt-in">
<div class="pop">
<h3>Northwind Pro</h3>
<p style="margin:7px 0 14px">The whole workspace, one payment. This card is the part — tip it.</p>
<div class="row"><span>Seats</span><b>Unlimited</b></div>
<div class="row"><span>Updates</span><b>Lifetime</b></div>
<div class="row"><span>Price</span><b>$129 once</b></div>
</div>
</div>
</div>
</div>/* KATA Tilt Card — perspective, a glare, one floating layer. */
.k-tilt{perspective:900px;font-family:var(--k-font);max-width:330px}
.k-tilt-in{position:relative;background:var(--k-zinc-950);color:var(--k-on-color);border-radius:16px;padding:22px;transform:rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg));transition:transform .3s ease-out;transform-style:preserve-3d;overflow:hidden}
.k-tilt.live .k-tilt-in{transition:transform .08s linear}
.k-tilt-in::after{content:"";position:absolute;inset:0;background:radial-gradient(340px circle at var(--gx,50%) var(--gy,50%), rgba(255,255,255,.14), transparent 65%);pointer-events:none}
.k-tilt .pop{transform:translateZ(34px)}
.k-tilt h3{font-size:17px;font-weight:650;letter-spacing:-.015em}
.k-tilt p{font-size:12.5px;line-height:1.75;color:var(--k-zinc-400)}
.k-tilt .row{display:flex;justify-content:space-between;font-size:12.5px;padding:8px 0;border-top:1px solid var(--k-zinc-800);color:var(--k-zinc-300)}
// KATA Tilt Card — a few degrees, a whisper of glare, then home.
document.querySelectorAll('[data-tilt]').forEach(function (wrap) {
var card = wrap.querySelector('.k-tilt-in');
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
wrap.addEventListener('pointermove', function (e) {
var r = wrap.getBoundingClientRect();
var px = (e.clientX - r.left) / r.width;
var py = (e.clientY - r.top) / r.height;
wrap.classList.add('live');
card.style.setProperty('--ry', ((px - .5) * 13).toFixed(2) + 'deg');
card.style.setProperty('--rx', ((.5 - py) * 11).toFixed(2) + 'deg');
card.style.setProperty('--gx', (px * 100).toFixed(1) + '%');
card.style.setProperty('--gy', (py * 100).toFixed(1) + '%');
});
wrap.addEventListener('pointerleave', function () {
wrap.classList.remove('live');
card.style.setProperty('--rx', '0deg');
card.style.setProperty('--ry', '0deg');
});
});
Installation
CLI
node kata-ui.mjs add tilt-card
Writes the part’s CSS and JS into your project. New to the CLI? See the CLI doc.
Manual
- Load
tokens.cssonce, before any part. - Copy the CSS tab into your stylesheet.
- Copy the HTML where it belongs. The part has a script — include it after the markup; it initializes itself.
Usage
One card per view earns this — a featured plan, a product shot, the thing being sold. The tilt caps at a few degrees, the glare is a whisper, and an inner layer floats on translateZ so the depth is real. The moment everything on the page tilts, nothing does.
Accessibility
The tilt is pointer-only garnish on a static card: content, order and actions are identical with the script removed, and touch and keyboard never trigger it. Under prefers-reduced-motion the card stays flat, which suits it fine.
Anatomy
The public surface of this part, read from its own source. Class names are the API — the CSS tab above is the full contract.
.k-tilt | class |
.k-tilt-in | class |
.live | class |
.pop | class |
.row | class |
data-tilt | data hook |
Related parts
Accordion Gallery beta
Five scenes in a row; the one you touch opens up and tells its caption.
Aurora beta
A slow wash of color behind a hero — the accent and the core, drifting under glass.
Beam border beta
A single point of light travels the edge of a card. The beam is the core color — the one accent, in motion.
Blur In beta
Words arrive out of focus and sharpen one after another, like eyes adjusting.