Mouse-Move Parallax Hero — Free HTML CSS JS Snippet
Mouse-Move Parallax Hero · Heroes · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Mouse-Move Parallax Hero — Layered Depth Effect Following the Cursor

This hero section responds to the mouse by shifting three stacked background layers at different speeds, creating an illusion of depth as the cursor moves — a common technique on modern marketing and product landing pages.
Layered depth via data-depth
Each .parallax-layer element carries a data-depth attribute (0.02 for the far starfield of dots, 0.05 for the mid blurred shapes, 0.1 for the closest shape). A higher depth value means the layer moves further per unit of mouse movement, so the "closest" layer visibly shifts the most while the "farthest" layer barely moves — mimicking how nearer objects appear to move faster than distant ones when your viewpoint shifts.
Smooth easing with a lerp loop
Raw mouse coordinates are jittery to translate directly into transforms, so the mousemove handler only updates a target {x, y} value. A separate requestAnimationFrame loop continuously moves a current {x, y} value toward that target using linear interpolation (lerp(a, b, 0.08)), producing a smooth trailing, slightly delayed motion rather than a jumpy 1:1 follow.
Applying the transform
On every animation frame, each layer's translate3d offset is computed as the negative of the eased cursor offset multiplied by its own depth value — moving layers in the opposite direction from the cursor, which is the direction real parallax layers move relative to a shifting viewpoint. translate3d is used specifically (rather than translate) to promote each layer to its own compositing layer for smoother, GPU-accelerated motion.
Resetting on mouse leave
When the cursor leaves the hero section, the target offset resets to {0, 0}, and the same lerp loop eases every layer smoothly back to its resting position rather than snapping instantly.
Step by step
How to Use
- 1Load the snippetClick "Mouse-Move Parallax Hero" in the sidebar to load its HTML, CSS, and JS into the editor panels. The preview updates instantly.
- 2Edit the codeModify any panel — HTML, CSS, or JS. The preview refreshes as you type. Use Reset in each panel header to restore the original.
- 3Preview on devicesClick the Mobile (375px), Tablet (768px), or Desktop buttons in the preview header to check responsiveness.
- 4Export in your formatClick "HTML" to download a standalone file, "JSX" for a React component, "Tailwind" for a React + Tailwind CSS component, "Tailwind HTML" for a standalone HTML file with Tailwind CDN, "Vue" for a Vue 3 SFC with <template>/<script setup>/<style scoped>, or "Angular" for a standalone Angular .component.ts file. "Copy all" copies the full code to clipboard.
- 5Save your versionClick "Save as", type a name, and press Enter. Your snippet saves to IndexedDB and appears in the Saved tab.
Real-world uses
Common Use Cases
translate3d transforms that are GPU accelerated and free from jank.data-depth value.Got questions?
Frequently Asked Questions
Directly following the raw cursor position produces a jittery, mechanical feel. Lerping the current position toward a target position each animation frame introduces a small, smooth delay that reads as fluid, natural motion instead.
Adjust the data-depth attribute on each .parallax-layer element. Larger values move that layer further per unit of mouse movement; smaller values keep a layer nearly still, simulating greater distance.
The effect is driven by mousemove, so it has no effect on pure touch interaction — the layers simply stay in their default position, which is an acceptable and common fallback for a purely decorative effect like this.
Build with AI
Build, Understand, Optimize, and Extend It With AI
Hand this snippet's HTML, CSS, and JavaScript to an AI coding assistant like Claude and ask it to adapt "Mouse-Move Parallax Hero" to your project — restyle it to match your design system, wire it up to real data instead of the static example, or port it to the framework you're building in.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a heroes component called "Mouse-Move Parallax Hero" using plain HTML, CSS, and vanilla JavaScript — no framework, no build step.
Requirements:
- Match the structure and behavior of the "Mouse-Move Parallax Hero" snippet from the UI Snippets Library.
- Keep the markup semantic and the styling self-contained (no external dependencies beyond what the original snippet uses).
- Keep the JavaScript vanilla, with no framework runtime required.
- Make it easy to restyle via CSS custom properties or class overrides so it can be dropped into a real project.Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
Source Code
<section class="ph-hero" id="phHero">
<div class="parallax-layer ph-layer-back" data-depth="0.02" id="phLayerBack">
<span class="ph-dot" style="top:10%;left:15%"></span>
<span class="ph-dot" style="top:30%;left:80%"></span>
<span class="ph-dot" style="top:70%;left:20%"></span>
<span class="ph-dot" style="top:85%;left:65%"></span>
<span class="ph-dot" style="top:50%;left:45%"></span>
<span class="ph-dot" style="top:20%;left:55%"></span>
</div>
<div class="parallax-layer ph-layer-mid" data-depth="0.05">
<span class="ph-shape ph-shape-a"></span>
<span class="ph-shape ph-shape-b"></span>
</div>
<div class="parallax-layer ph-layer-front" data-depth="0.1">
<span class="ph-shape ph-shape-c"></span>
</div>
<div class="ph-content">
<h1>Build interfaces<br />that feel alive</h1>
<p>A subtle mouse-driven parallax hero — move your cursor to see the depth.</p>
<button class="ph-cta">Get Started</button>
</div>
</section>*{box-sizing:border-box}
body{font-family:system-ui,-apple-system,sans-serif;margin:0}
.ph-hero{position:relative;width:100%;height:100vh;min-height:480px;background:radial-gradient(circle at 30% 20%,#1e1b4b,#0b0d1a 70%);overflow:hidden;display:flex;align-items:center;justify-content:center}
.parallax-layer{position:absolute;inset:0;pointer-events:none;will-change:transform}
.ph-dot{position:absolute;width:4px;height:4px;border-radius:50%;background:rgba(255,255,255,.5)}
.ph-shape{position:absolute;border-radius:50%;filter:blur(50px);opacity:.55}
.ph-shape-a{width:280px;height:280px;background:#6366f1;top:15%;left:10%}
.ph-shape-b{width:220px;height:220px;background:#ec4899;bottom:10%;right:12%}
.ph-shape-c{width:160px;height:160px;background:#22d3ee;top:55%;left:60%;filter:blur(60px);opacity:.35}
.ph-content{position:relative;z-index:2;text-align:center;color:#fff;padding:24px;max-width:600px}
.ph-content h1{font-size:clamp(28px,5vw,48px);font-weight:800;line-height:1.15;margin:0 0 14px;letter-spacing:-.02em}
.ph-content p{font-size:15px;color:#c7cbe0;margin:0 0 24px;line-height:1.6}
.ph-cta{padding:13px 28px;border-radius:999px;border:none;background:#fff;color:#0b0d1a;font-size:14px;font-weight:700;cursor:pointer;font-family:inherit;transition:transform .15s}
.ph-cta:hover{transform:translateY(-2px)}var hero = document.getElementById('phHero');
var layers = Array.prototype.slice.call(document.querySelectorAll('.parallax-layer'));
var target = { x: 0, y: 0 };
var current = { x: 0, y: 0 };
var rafId = null;
function onMouseMove(e) {
var rect = hero.getBoundingClientRect();
var cx = rect.left + rect.width / 2;
var cy = rect.top + rect.height / 2;
target.x = e.clientX - cx;
target.y = e.clientY - cy;
}
function onMouseLeave() {
target.x = 0;
target.y = 0;
}
function lerp(a, b, t) {
return a + (b - a) * t;
}
function animate() {
current.x = lerp(current.x, target.x, 0.08);
current.y = lerp(current.y, target.y, 0.08);
layers.forEach(function (layer) {
var depth = parseFloat(layer.getAttribute('data-depth')) || 0;
var moveX = -current.x * depth;
var moveY = -current.y * depth;
layer.style.transform = 'translate3d(' + moveX.toFixed(2) + 'px,' + moveY.toFixed(2) + 'px,0)';
});
rafId = requestAnimationFrame(animate);
}
hero.addEventListener('mousemove', onMouseMove);
hero.addEventListener('mouseleave', onMouseLeave);
animate();



