webdevpuneet.com

Hero with 3D Tilting Product Mockup — Free HTML CSS JS Snippet

Hero with 3D Tilting Product Mockup · Heroes · Plain HTML, CSS & JS · Live preview

CategoryHeroes

Copy & paste

Source Code

<section class="tlt-hero">
  <div class="tlt-copy">
    <span class="tlt-eyebrow">New — Studio 4.0</span>
    <h1 class="tlt-h1">Design software<br>that moves with you</h1>
    <p class="tlt-sub">A canvas that responds to every gesture. Move your cursor over the mockup — it's really tracking you, not just playing an animation.</p>
    <a href="#" class="tlt-cta">Download for free</a>
  </div>

  <div class="tlt-stage" id="tltStage">
    <div class="tlt-card" id="tltCard">
      <div class="tlt-glare" id="tltGlare"></div>
      <div class="tlt-screen">
        <div class="tlt-topbar">
          <span></span><span></span><span></span>
        </div>
        <div class="tlt-bars">
          <div class="tlt-bar" style="width:78%"></div>
          <div class="tlt-bar" style="width:52%"></div>
          <div class="tlt-bar" style="width:64%"></div>
        </div>
        <div class="tlt-blocks">
          <div class="tlt-block"></div>
          <div class="tlt-block"></div>
          <div class="tlt-block"></div>
        </div>
      </div>
    </div>
  </div>
</section>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Real pointer-tracked rotation
rotateX/rotateY derived from live cursor position.
Proportional tilt
Rotation scales continuously with distance from center.
3D depth via translateZ
Screen content sits visibly above the card base.
Cursor-synced glare
Highlight position matches the same px/py as the tilt.
Smooth return to rest
pointerleave eases back to flat, not an instant cut.
perspective + preserve-3d
Correct CSS 3D context for real depth.
Abstract mockup UI
Drop-in placeholder for a real screenshot.
No dependencies
Pure vanilla JS pointer math.

About this UI Snippet

Hero with 3D Tilting Product Mockup — Cursor-Tracked Tilt and Glare

Screenshot of the Hero with 3D Tilting Product Mockup snippet rendered live

A product mockup that "tilts toward" the cursor is a small detail that reads as expensive craftsmanship — but only if it's actually tracking the pointer. This snippet computes real rotateX/rotateY values from the cursor's live position over the hero every frame, rather than looping a fixed CSS keyframe animation that ignores where the mouse actually is.

The math behind the tilt

On every pointermove over the stage, the handler reads getBoundingClientRect() to get the stage's live position and size, then computes the cursor's position as a 0–1 fraction of the stage's width and height (px, py). Centering that fraction around 0.5 and multiplying by MAX_TILT produces a signed rotation: cursor at the left edge yields a negative rotateY, cursor at the right edge yields a positive one, and the card sits flat at dead center. This is a direct, continuous function of pointer position — move the cursor one pixel, the rotation updates by a proportional fraction of a degree.

Why perspective and transform-style matter

.tlt-stage sets perspective: 1200px — without it, rotateX/rotateY on the card would have no visible depth, just a 2D squash. .tlt-card sets transform-style: preserve-3d so its child elements (the screen content) can be pushed forward in 3D space rather than being flattened onto the card's own plane; .tlt-screen uses translateZ(30px) to sit visibly above the card's base surface, giving the tilt actual depth rather than looking like a rotated flat image.

A glare that moves with the tilt, not against it

The glare layer's radial-gradient center position is recalculated every pointermove from the same px/py fractions driving the rotation — so the highlight tracks the same point the cursor is "pushing" toward, the way light behaves on a real glossy surface being tilted, rather than sitting static or drifting independently of the tilt.

A clean return to rest

pointerleave resets both the transform and the glare opacity, with the CSS transition on .tlt-card easing the snap back to flat rather than the card cutting instantly to rotateX(0) rotateY(0).

Customizing it

Adjust MAX_TILT for a subtler or more dramatic effect, add more translateZ layers inside .tlt-screen for a deeper parallax stack, or swap the abstract UI mockup for a real product screenshot. Pair it with 3D card tilt or tilt glow card for the same technique on a smaller card component, or gradient mesh hero for a different hero backdrop.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSThe hero renders with the mockup flat at rest.
  2. 2
    Move the cursor over the mockup areaThe card tilts toward your cursor in real 3D, tracking it continuously.
  3. 3
    Move to the edgesRotation increases toward MAX_TILT as the cursor approaches the stage bounds.
  4. 4
    Move the cursor awayThe card eases back to flat and the glare fades out.
  5. 5
    Tune MAX_TILTIncrease for a more dramatic tilt, decrease for subtlety.
  6. 6
    Swap the mockup contentReplace .tlt-screen's contents with a real screenshot or iframe.

Real-world uses

Common Use Cases

Creative tool landing pages
Show off a canvas product with a mockup that tilts toward the cursor, with rotateX and rotateY computed from the live pointer position.
Hardware and device launches
Tilt a rendered device in real 3D, with screen content floating above the card base through translateZ for visible depth.
Phone mockup tilt pairing
Pair with an app hero for a phone mockup that responds to the pointer, with a glare synchronised to the same tilt values.
Portfolio flagship projects
Feature a standout piece with proportional tilt that scales with distance from the centre of the card.
Premium product pages
Signal craftsmanship, and complement a grid of 3D card tilt tiles elsewhere on a showcase page.
Related: Hero with Feature Tabs Preview
See the Hero with Feature Tabs Preview for a related heroes pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

On pointermove, the handler reads the stage's live bounding rect, converts the cursor's clientX/clientY into a 0-1 fraction of the stage width and height, centers that fraction around 0.5, and multiplies by MAX_TILT to get signed rotateX/rotateY degrees. Because this runs on every pointermove event with the current cursor position, the rotation is a continuous function of where the cursor actually is — not a looping animation.

perspective on the parent stage establishes the 3D viewing distance — without it, rotateX/rotateY would just squash the card in 2D with no sense of depth. transform-style: preserve-3d on the card lets its child .tlt-screen element (pushed forward with translateZ) render in true 3D space relative to the card's rotation, instead of being flattened onto the card's own 2D plane.

The glare's radial-gradient center position is set from the exact same px and py fractions (0-1 cursor position within the stage) used to compute the rotation, on the same pointermove event. Since both are derived from one shared position, the highlight always sits toward the side the card is tilting toward, mimicking how light reflects off a real glossy surface as it's turned.

A pointerleave listener resets the card's transform to rotateX(0deg) rotateY(0deg) scale(1) and the glare's opacity to 0. Because .tlt-card has a CSS transition on transform, the card eases smoothly back to flat rather than snapping instantly, which reads as a natural settle rather than a glitch.

Attach the pointermove and pointerleave listeners in a mount effect (useEffect in React, onMounted in Vue) scoped to the stage ref, and clean them up on unmount. Since the effect only ever writes to style.transform and the glare's background via refs, it works the same way regardless of framework — no state re-renders are needed per pointer move if you write directly to the DOM node.