UI Component
✨ NewMarketing

3D Parallax Hero Section with Device Mockups

A modern SaaS landing hero with a CSS 3D laptop and phone mockup that tilts with your mouse, parallax gradient-mesh blobs, a rotating headline word, social proof and an infinite logo marquee. The dashboard inside the mockup is drawn with pure CSS and an animated SVG chart — no images needed.

September 26, 20263 views
  • Hero Section
  • hero-section
  • 3d
  • parallax
  • landing-page
  • mockup
  • saas
  • css-animation
3D Parallax Hero Section with Device Mockups
Free

Download instantly, no signup required.

Features Included

CSS 3D laptop + phone mockup that tilts with the mouse
Fake dashboard UI inside the laptop with an animated SVG line chart
Parallax gradient-mesh background blobs and a faded grid
Rotating headline word (design → build → launch → scale)
Floating notification chips at different 3D depths
Social proof avatars + rating and an infinite logo marquee
Fully responsive, respects prefers-reduced-motion
Dependencies
Google Fonts — Plus Jakarta Sanscdn

3D Parallax Hero Section with Device Mockups

A landing-page hero that feels alive — 3D device mockups that follow your cursor, a rotating headline word and a trusted-by logo marquee. Pure HTML, CSS and vanilla JavaScript, zero images.


What's Included

  • CSS 3D laptop + phone mockup that tilts with the mouse
  • Fake dashboard UI inside the laptop with an animated SVG line chart
  • Parallax gradient-mesh background blobs and a faded grid
  • Rotating headline word (design → build → launch → scale)
  • Floating notification chips at different 3D depths
  • Social proof avatars + rating and an infinite logo marquee
  • Fully responsive, respects prefers-reduced-motion

Dependencies

Already linked inside the component's files — no extra setup needed.


Desktop Preview

Screenshot 2026-09-27 021942.png


HTML

html
1<!doctype html>
2<html lang="en">
3  <head>
4    <meta charset="UTF-8" />
5    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6    <title>3D Parallax Device Hero | MetaSkillGroup</title>
7    <link rel="stylesheet" href="style.css" />
8  </head>
9  <body>
10    <!-- created by metaskillgroup-team -->
11    <section class="hero">
12      <!-- Gradient mesh blobs -->
13      <div class="mesh" aria-hidden="true">
14        <span class="blob b1" data-depth="30"></span>
15        <span class="blob b2" data-depth="-40"></span>
16        <span class="blob b3" data-depth="20"></span>
17      </div>
18      <div class="grid-lines" aria-hidden="true"></div>
19
20      <div class="hero-inner">
21        <!-- Copy -->
22        <div class="hero-copy">
23          <a href="#" class="announce">
24            <span class="announce-tag">New</span>
25            Series A — we raised $24M
26            <svg viewBox="0 0 24 24" width="16" height="16"><path d="M9 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
27          </a>
28
29          <h1>
30            The workspace to<br />
31            <span class="rotator" aria-live="polite">
32              <span class="word is-active">design</span>
33              <span class="word">build</span>
34              <span class="word">launch</span>
35              <span class="word">scale</span>
36            </span>
37            <br />your next product.
38          </h1>
39
40          <p class="lead">
41            Plan, ship and measure in one fast, beautiful tool. Loved by 40,000+
42            teams who are done juggling ten different apps.
43          </p>
44
45          <div class="cta-row">
46            <a href="#" class="btn btn-primary">
47              Start for free
48              <svg viewBox="0 0 24 24" width="18" height="18"><path d="M5 12h14M13 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
49            </a>
50            <a href="#" class="btn btn-ghost">
51              <span class="play">
52                <svg viewBox="0 0 24 24" width="14" height="14"><path d="M8 5v14l11-7z" fill="currentColor"/></svg>
53              </span>
54              Watch demo
55            </a>
56          </div>
57
58          <div class="social-proof">
59            <div class="avatars">
60              <span style="--h: 260">AK</span>
61              <span style="--h: 190">RS</span>
62              <span style="--h: 330">MJ</span>
63              <span style="--h: 30">PL</span>
64            </div>
65            <div>
66              <div class="stars">★★★★★</div>
67              <small>4.9/5 from 2,300+ reviews</small>
68            </div>
69          </div>
70        </div>
71
72        <!-- 3D devices -->
73        <div class="scene" aria-hidden="true">
74          <div class="devices">
75            <!-- Laptop -->
76            <div class="laptop">
77              <div class="laptop-screen">
78                <div class="app">
79                  <div class="app-side">
80                    <span class="dot-logo"></span>
81                    <i></i><i class="on"></i><i></i><i></i>
82                  </div>
83                  <div class="app-main">
84                    <div class="app-top">
85                      <b></b>
86                      <span class="pill"></span>
87                    </div>
88                    <div class="app-kpis">
89                      <div class="kpi"><small></small><strong>$48.2k</strong><em>+12%</em></div>
90                      <div class="kpi"><small></small><strong>3,904</strong><em>+8%</em></div>
91                      <div class="kpi"><small></small><strong>72%</strong><em>+4%</em></div>
92                    </div>
93                    <div class="app-chart">
94                      <svg viewBox="0 0 300 100" preserveAspectRatio="none">
95                        <defs>
96                          <linearGradient id="area" x1="0" y1="0" x2="0" y2="1">
97                            <stop offset="0" stop-color="#7c5cff" stop-opacity=".45" />
98                            <stop offset="1" stop-color="#7c5cff" stop-opacity="0" />
99                          </linearGradient>
100                        </defs>
101                        <path class="chart-area" d="M0 80 C30 70 45 40 75 45 S120 75 150 50 S200 15 230 25 S275 10 300 5 V100 H0Z" fill="url(#area)" />
102                        <path class="chart-line" d="M0 80 C30 70 45 40 75 45 S120 75 150 50 S200 15 230 25 S275 10 300 5" fill="none" stroke="#7c5cff" stroke-width="3" />
103                      </svg>
104                    </div>
105                    <div class="app-rows">
106                      <i></i><i></i><i></i>
107                    </div>
108                  </div>
109                </div>
110              </div>
111              <div class="laptop-base"></div>
112            </div>
113
114            <!-- Phone -->
115            <div class="phone">
116              <div class="phone-notch"></div>
117              <div class="phone-screen">
118                <small>Revenue</small>
119                <strong>$12,480</strong>
120                <div class="bars">
121                  <i style="--v: 40%"></i><i style="--v: 65%"></i><i style="--v: 50%"></i>
122                  <i style="--v: 85%"></i><i style="--v: 70%"></i><i style="--v: 95%"></i>
123                </div>
124                <div class="phone-card"><span></span><b></b></div>
125                <div class="phone-card"><span class="c2"></span><b></b></div>
126              </div>
127            </div>
128
129            <!-- Floating chips -->
130            <div class="chip chip-1">
131              <span class="chip-icon">✓</span>
132              <div><strong>Deploy complete</strong><small>2 seconds ago</small></div>
133            </div>
134            <div class="chip chip-2">
135              <span class="chip-icon c2">↑</span>
136              <div><strong>+38% growth</strong><small>this quarter</small></div>
137            </div>
138          </div>
139        </div>
140      </div>
141
142      <!-- Logo marquee -->
143      <div class="logos">
144        <p>Trusted by teams at</p>
145        <div class="marquee">
146          <div class="marquee-track">
147            <span>◆ Northwind</span><span>● Lumen</span><span>▲ Vertex</span><span>■ Quanta</span>
148            <span>✦ Orbit</span><span>◆ Helix</span><span>● Pulse</span><span>▲ Nimbus</span>
149          </div>
150        </div>
151      </div>
152    </section>
153
154    <script src="script.js"></script>
155  </body>
156</html>
157

CSS

css
1/* Importing Google Fonts - Plus Jakarta Sans */
2@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap");
3
4* {
5  margin: 0;
6  padding: 0;
7  box-sizing: border-box;
8  font-family: "Plus Jakarta Sans", sans-serif;
9}
10
11:root {
12  --bg: #f7f6ff;
13  --text: #14122b;
14  --muted: #5f5d7a;
15  --accent: #7c5cff;
16  --accent-2: #ff6ba6;
17  --accent-3: #2dd4bf;
18  --card: #ffffff;
19  --border: rgba(20, 18, 43, 0.08);
20}
21
22body {
23  background: var(--bg);
24  color: var(--text);
25  overflow-x: hidden;
26}
27
28a {
29  color: inherit;
30  text-decoration: none;
31}
32
33/* ---------- Hero shell ---------- */
34.hero {
35  position: relative;
36  min-height: 100vh;
37  display: flex;
38  flex-direction: column;
39  justify-content: center;
40  padding: 80px 24px 40px;
41  overflow: hidden;
42  isolation: isolate;
43}
44
45.mesh {
46  position: absolute;
47  inset: 0;
48  z-index: -2;
49}
50
51.blob {
52  position: absolute;
53  border-radius: 50%;
54  filter: blur(80px);
55  opacity: 0.55;
56  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
57}
58
59.b1 {
60  width: 520px;
61  height: 520px;
62  background: #b9a8ff;
63  top: -160px;
64  left: -120px;
65}
66
67.b2 {
68  width: 460px;
69  height: 460px;
70  background: #ffc2dc;
71  bottom: -140px;
72  right: 10%;
73}
74
75.b3 {
76  width: 360px;
77  height: 360px;
78  background: #a7f3e8;
79  top: 20%;
80  right: -120px;
81}
82
83.grid-lines {
84  position: absolute;
85  inset: 0;
86  z-index: -1;
87  background-image:
88    linear-gradient(var(--border) 1px, transparent 1px),
89    linear-gradient(90deg, var(--border) 1px, transparent 1px);
90  background-size: 56px 56px;
91  mask-image: radial-gradient(ellipse at center, #000 20%, transparent 70%);
92  -webkit-mask-image: radial-gradient(ellipse at center, #000 20%, transparent 70%);
93}
94
95.hero-inner {
96  width: 100%;
97  max-width: 1240px;
98  margin: 0 auto;
99  display: grid;
100  grid-template-columns: 1fr 1.1fr;
101  align-items: center;
102  gap: 48px;
103}
104
105/* ---------- Copy ---------- */
106.announce {
107  display: inline-flex;
108  align-items: center;
109  gap: 10px;
110  padding: 6px 14px 6px 6px;
111  border-radius: 99px;
112  font-size: 0.85rem;
113  font-weight: 600;
114  background: rgba(255, 255, 255, 0.7);
115  border: 1px solid var(--border);
116  backdrop-filter: blur(8px);
117  box-shadow: 0 4px 16px rgba(124, 92, 255, 0.08);
118  transition: transform 0.2s ease;
119}
120
121.announce:hover {
122  transform: translateY(-2px);
123}
124
125.announce-tag {
126  padding: 3px 10px;
127  border-radius: 99px;
128  color: #fff;
129  font-size: 0.75rem;
130  background: linear-gradient(135deg, var(--accent), var(--accent-2));
131}
132
133h1 {
134  margin: 24px 0 20px;
135  font-size: clamp(2.4rem, 5.2vw, 4.2rem);
136  font-weight: 800;
137  line-height: 1.08;
138  letter-spacing: -0.04em;
139}
140
141/* Rotating headline word */
142.rotator {
143  position: relative;
144  display: inline-block;
145  height: 1.12em;
146  min-width: 4.2em;
147  vertical-align: bottom;
148  overflow: hidden;
149}
150
151.word {
152  position: absolute;
153  left: 0;
154  top: 0;
155  background: linear-gradient(90deg, var(--accent), var(--accent-2));
156  -webkit-background-clip: text;
157  background-clip: text;
158  color: transparent;
159  transform: translateY(110%);
160  opacity: 0;
161  transition:
162    transform 0.6s cubic-bezier(0.22, 1, 0.36, 1),
163    opacity 0.4s ease;
164}
165
166.word.is-active {
167  transform: translateY(0);
168  opacity: 1;
169}
170
171.word.is-leaving {
172  transform: translateY(-110%);
173  opacity: 0;
174}
175
176.lead {
177  max-width: 480px;
178  font-size: 1.1rem;
179  line-height: 1.7;
180  color: var(--muted);
181}
182
183.cta-row {
184  display: flex;
185  flex-wrap: wrap;
186  gap: 12px;
187  margin-top: 32px;
188}
189
190.btn {
191  display: inline-flex;
192  align-items: center;
193  gap: 10px;
194  padding: 14px 24px;
195  border-radius: 14px;
196  font-weight: 700;
197  font-size: 0.98rem;
198  transition:
199    transform 0.2s ease,
200    box-shadow 0.2s ease;
201}
202
203.btn-primary {
204  color: #fff;
205  background: var(--text);
206  box-shadow: 0 10px 30px rgba(20, 18, 43, 0.25);
207}
208
209.btn-primary:hover {
210  transform: translateY(-2px);
211  box-shadow: 0 16px 36px rgba(124, 92, 255, 0.35);
212  background: linear-gradient(135deg, var(--accent), #5b6cff);
213}
214
215.btn-primary svg {
216  transition: transform 0.2s ease;
217}
218
219.btn-primary:hover svg {
220  transform: translateX(3px);
221}
222
223.btn-ghost {
224  background: rgba(255, 255, 255, 0.75);
225  border: 1px solid var(--border);
226}
227
228.btn-ghost:hover {
229  transform: translateY(-2px);
230}
231
232.play {
233  display: grid;
234  place-items: center;
235  width: 28px;
236  height: 28px;
237  border-radius: 50%;
238  color: #fff;
239  background: var(--accent);
240  box-shadow: 0 0 0 0 rgba(124, 92, 255, 0.5);
241  animation: pulse 2s infinite;
242}
243
244@keyframes pulse {
245  70% {
246    box-shadow: 0 0 0 10px rgba(124, 92, 255, 0);
247  }
248  100% {
249    box-shadow: 0 0 0 0 rgba(124, 92, 255, 0);
250  }
251}
252
253.social-proof {
254  display: flex;
255  align-items: center;
256  gap: 14px;
257  margin-top: 36px;
258}
259
260.avatars {
261  display: flex;
262}
263
264.avatars span {
265  display: grid;
266  place-items: center;
267  width: 38px;
268  height: 38px;
269  margin-left: -10px;
270  border-radius: 50%;
271  border: 3px solid var(--bg);
272  font-size: 0.72rem;
273  font-weight: 700;
274  color: #fff;
275  background: hsl(var(--h) 70% 60%);
276}
277
278.avatars span:first-child {
279  margin-left: 0;
280}
281
282.stars {
283  color: #f59e0b;
284  letter-spacing: 2px;
285}
286
287.social-proof small {
288  color: var(--muted);
289  font-size: 0.82rem;
290}
291
292/* ---------- 3D scene ---------- */
293.scene {
294  perspective: 1400px;
295  height: 520px;
296  display: grid;
297  place-items: center;
298}
299
300.devices {
301  --rx: 8deg;
302  --ry: -18deg;
303  position: relative;
304  width: 560px;
305  height: 380px;
306  transform-style: preserve-3d;
307  transform: rotateX(var(--rx)) rotateY(var(--ry));
308  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
309  animation: float 6s ease-in-out infinite;
310}
311
312@keyframes float {
313  50% {
314    translate: 0 -12px;
315  }
316}
317
318/* Laptop */
319.laptop {
320  position: absolute;
321  inset: 0;
322  transform-style: preserve-3d;
323}
324
325.laptop-screen {
326  position: absolute;
327  top: 0;
328  left: 30px;
329  right: 30px;
330  height: 330px;
331  padding: 12px;
332  border-radius: 18px 18px 6px 6px;
333  background: #1b1930;
334  box-shadow:
335    0 0 0 2px #2c2947 inset,
336    0 40px 80px rgba(20, 18, 43, 0.35);
337}
338
339.laptop-base {
340  position: absolute;
341  bottom: 30px;
342  left: 0;
343  right: 0;
344  height: 18px;
345  border-radius: 4px 4px 18px 18px;
346  background: linear-gradient(180deg, #d9d7ea, #aeabc6);
347  box-shadow: 0 20px 40px rgba(20, 18, 43, 0.25);
348}
349
350.laptop-base::before {
351  content: "";
352  position: absolute;
353  top: 0;
354  left: 50%;
355  width: 90px;
356  height: 7px;
357  transform: translateX(-50%);
358  border-radius: 0 0 8px 8px;
359  background: #9895b3;
360}
361
362/* Fake dashboard UI inside the laptop */
363.app {
364  display: flex;
365  height: 100%;
366  border-radius: 8px;
367  overflow: hidden;
368  background: #fbfaff;
369}
370
371.app-side {
372  display: flex;
373  flex-direction: column;
374  gap: 10px;
375  width: 54px;
376  padding: 12px 10px;
377  background: #f0eefc;
378}
379
380.dot-logo {
381  width: 26px;
382  height: 26px;
383  margin: 0 auto 8px;
384  border-radius: 8px;
385  background: linear-gradient(135deg, var(--accent), var(--accent-2));
386}
387
388.app-side i {
389  height: 22px;
390  border-radius: 7px;
391  background: #e1ddf7;
392}
393
394.app-side i.on {
395  background: var(--accent);
396}
397
398.app-main {
399  flex: 1;
400  display: flex;
401  flex-direction: column;
402  gap: 10px;
403  padding: 12px;
404}
405
406.app-top {
407  display: flex;
408  justify-content: space-between;
409  align-items: center;
410}
411
412.app-top b {
413  width: 110px;
414  height: 12px;
415  border-radius: 6px;
416  background: #2a2745;
417}
418
419.app-top .pill {
420  width: 60px;
421  height: 20px;
422  border-radius: 99px;
423  background: var(--accent);
424}
425
426.app-kpis {
427  display: grid;
428  grid-template-columns: repeat(3, 1fr);
429  gap: 8px;
430}
431
432.kpi {
433  display: flex;
434  flex-direction: column;
435  gap: 4px;
436  padding: 8px 10px;
437  border-radius: 10px;
438  background: #fff;
439  border: 1px solid #ecebf5;
440}
441
442.kpi small {
443  width: 50%;
444  height: 6px;
445  border-radius: 3px;
446  background: #d6d3ea;
447}
448
449.kpi strong {
450  font-size: 0.85rem;
451}
452
453.kpi em {
454  font-style: normal;
455  font-size: 0.62rem;
456  font-weight: 700;
457  color: #10b981;
458}
459
460.app-chart {
461  flex: 1;
462  padding: 8px;
463  border-radius: 10px;
464  background: #fff;
465  border: 1px solid #ecebf5;
466}
467
468.app-chart svg {
469  width: 100%;
470  height: 100%;
471}
472
473.chart-line {
474  stroke-dasharray: 500;
475  stroke-dashoffset: 500;
476  animation: draw 2.4s 0.4s cubic-bezier(0.22, 1, 0.36, 1) forwards;
477}
478
479.chart-area {
480  opacity: 0;
481  animation: fade 1s 1.4s forwards;
482}
483
484@keyframes draw {
485  to {
486    stroke-dashoffset: 0;
487  }
488}
489
490@keyframes fade {
491  to {
492    opacity: 1;
493  }
494}
495
496.app-rows {
497  display: flex;
498  flex-direction: column;
499  gap: 6px;
500}
501
502.app-rows i {
503  height: 10px;
504  border-radius: 5px;
505  background: #eceaf7;
506}
507
508.app-rows i:nth-child(2) {
509  width: 80%;
510}
511
512.app-rows i:nth-child(3) {
513  width: 60%;
514}
515
516/* Phone */
517.phone {
518  position: absolute;
519  right: -30px;
520  bottom: 10px;
521  width: 150px;
522  height: 300px;
523  padding: 10px;
524  border-radius: 30px;
525  background: #1b1930;
526  transform: translateZ(90px);
527  box-shadow:
528    0 0 0 2px #2c2947 inset,
529    -20px 40px 60px rgba(20, 18, 43, 0.35);
530}
531
532.phone-notch {
533  position: absolute;
534  top: 14px;
535  left: 50%;
536  width: 46px;
537  height: 12px;
538  transform: translateX(-50%);
539  border-radius: 99px;
540  background: #1b1930;
541  z-index: 1;
542}
543
544.phone-screen {
545  display: flex;
546  flex-direction: column;
547  gap: 6px;
548  height: 100%;
549  padding: 34px 12px 12px;
550  border-radius: 22px;
551  background: linear-gradient(180deg, #7c5cff, #5b3fe0);
552  color: #fff;
553}
554
555.phone-screen small {
556  font-size: 0.65rem;
557  opacity: 0.8;
558}
559
560.phone-screen strong {
561  font-size: 1.1rem;
562}
563
564.bars {
565  display: flex;
566  align-items: flex-end;
567  gap: 5px;
568  height: 80px;
569  margin: 6px 0 10px;
570}
571
572.bars i {
573  flex: 1;
574  height: var(--v);
575  border-radius: 4px;
576  background: rgba(255, 255, 255, 0.85);
577  transform-origin: bottom;
578  animation: grow 1s cubic-bezier(0.22, 1, 0.36, 1) both;
579}
580
581.bars i:nth-child(2) { animation-delay: 0.1s; }
582.bars i:nth-child(3) { animation-delay: 0.2s; }
583.bars i:nth-child(4) { animation-delay: 0.3s; }
584.bars i:nth-child(5) { animation-delay: 0.4s; }
585.bars i:nth-child(6) { animation-delay: 0.5s; }
586
587@keyframes grow {
588  from {
589    transform: scaleY(0);
590  }
591}
592
593.phone-card {
594  display: flex;
595  align-items: center;
596  gap: 8px;
597  padding: 8px;
598  border-radius: 10px;
599  background: rgba(255, 255, 255, 0.15);
600}
601
602.phone-card span {
603  width: 20px;
604  height: 20px;
605  border-radius: 6px;
606  background: var(--accent-3);
607}
608
609.phone-card span.c2 {
610  background: var(--accent-2);
611}
612
613.phone-card b {
614  flex: 1;
615  height: 6px;
616  border-radius: 3px;
617  background: rgba(255, 255, 255, 0.6);
618}
619
620/* Floating chips */
621.chip {
622  position: absolute;
623  display: flex;
624  align-items: center;
625  gap: 10px;
626  padding: 10px 14px;
627  border-radius: 14px;
628  background: rgba(255, 255, 255, 0.85);
629  backdrop-filter: blur(10px);
630  border: 1px solid var(--border);
631  box-shadow: 0 20px 40px rgba(20, 18, 43, 0.15);
632  white-space: nowrap;
633}
634
635.chip strong {
636  display: block;
637  font-size: 0.82rem;
638}
639
640.chip small {
641  font-size: 0.7rem;
642  color: var(--muted);
643}
644
645.chip-icon {
646  display: grid;
647  place-items: center;
648  width: 30px;
649  height: 30px;
650  border-radius: 9px;
651  font-weight: 800;
652  color: #fff;
653  background: #10b981;
654}
655
656.chip-icon.c2 {
657  background: var(--accent-2);
658}
659
660.chip-1 {
661  top: 40px;
662  left: -50px;
663  transform: translateZ(140px);
664}
665
666.chip-2 {
667  bottom: -10px;
668  left: 60px;
669  transform: translateZ(120px);
670}
671
672/* ---------- Logo marquee ---------- */
673.logos {
674  max-width: 1240px;
675  width: 100%;
676  margin: 56px auto 0;
677  text-align: center;
678}
679
680.logos p {
681  font-size: 0.8rem;
682  font-weight: 700;
683  letter-spacing: 0.1em;
684  text-transform: uppercase;
685  color: var(--muted);
686}
687
688.marquee {
689  margin-top: 18px;
690  overflow: hidden;
691  mask-image: linear-gradient(90deg, transparent, #000 15%, #000 85%, transparent);
692  -webkit-mask-image: linear-gradient(90deg, transparent, #000 15%, #000 85%, transparent);
693}
694
695.marquee-track {
696  display: flex;
697  gap: 56px;
698  width: max-content;
699  animation: scroll 28s linear infinite;
700}
701
702.marquee-track span {
703  font-size: 1.35rem;
704  font-weight: 800;
705  letter-spacing: -0.02em;
706  color: #9a97b5;
707  transition: color 0.2s ease;
708}
709
710.marquee-track span:hover {
711  color: var(--text);
712}
713
714.marquee:hover .marquee-track {
715  animation-play-state: paused;
716}
717
718@keyframes scroll {
719  to {
720    transform: translateX(calc(-50% - 28px));
721  }
722}
723
724/* ---------- Responsive ---------- */
725@media (max-width: 1024px) {
726  .hero-inner {
727    grid-template-columns: 1fr;
728    text-align: center;
729  }
730
731  .lead {
732    margin: 0 auto;
733  }
734
735  .cta-row,
736  .social-proof {
737    justify-content: center;
738  }
739
740  .scene {
741    height: 460px;
742  }
743}
744
745@media (max-width: 640px) {
746  .hero {
747    padding-top: 56px;
748  }
749
750  .scene {
751    height: 340px;
752  }
753
754  .devices {
755    scale: 0.6;
756  }
757}
758
759@media (max-width: 400px) {
760  .devices {
761    scale: 0.5;
762  }
763}
764
765@media (prefers-reduced-motion: reduce) {
766  *,
767  *::before,
768  *::after {
769    animation: none !important;
770    transition-duration: 0.01ms !important;
771  }
772
773  .chart-line {
774    stroke-dashoffset: 0;
775  }
776
777  .chart-area {
778    opacity: 1;
779  }
780}

JavaScript

javascript
1const hero = document.querySelector(".hero");
2const devices = document.querySelector(".devices");
3const blobs = document.querySelectorAll(".blob");
4const words = document.querySelectorAll(".rotator .word");
5const track = document.querySelector(".marquee-track");
6
7const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
8
9// Rotating headline word
10let current = 0;
11if (!reduceMotion) {
12  setInterval(() => {
13    const prev = words[current];
14    current = (current + 1) % words.length;
15    const next = words[current];
16
17    prev.classList.remove("is-active");
18    prev.classList.add("is-leaving");
19    next.classList.remove("is-leaving");
20    next.classList.add("is-active");
21
22    // Reset the leaving word below the line so it can slide in again later
23    setTimeout(() => prev.classList.remove("is-leaving"), 600);
24  }, 2200);
25}
26
27// Mouse-driven 3D tilt for the devices + parallax for the background blobs
28const BASE_RX = 8;
29const BASE_RY = -18;
30
31const tilt = (x, y) => {
32  // x, y are in the range -0.5 .. 0.5
33  devices.style.setProperty("--rx", `${BASE_RX - y * 16}deg`);
34  devices.style.setProperty("--ry", `${BASE_RY + x * 28}deg`);
35  blobs.forEach((blob) => {
36    const depth = Number(blob.dataset.depth);
37    blob.style.transform = `translate(${x * depth}px, ${y * depth}px)`;
38  });
39};
40
41if (!reduceMotion && window.matchMedia("(pointer: fine)").matches) {
42  hero.addEventListener("mousemove", (e) => {
43    const rect = hero.getBoundingClientRect();
44    tilt((e.clientX - rect.left) / rect.width - 0.5, (e.clientY - rect.top) / rect.height - 0.5);
45  });
46  hero.addEventListener("mouseleave", () => tilt(0, 0));
47}
48
49// Duplicate logos so the marquee loops seamlessly
50track.innerHTML += track.innerHTML;
51

Built by Meta Skill Group — copy it, use it, make it yours.

Built With

🌐

HTML5

⚡

JavaScript

🎨

CSS3

Compatibility

Browsers
ChromeOperaBraveFirefoxSafariArcVivaldiEdge
Devices
DesktopSmartwatchTVTabletMobile
Frameworks
Vanilla JSHTML/CSS

Found this useful?

MetaSkillGroup

Written by

MetaSkillGroup

September 26, 2026

❓ FAQs

Subscribe to Newsletter

Get latest updates, tutorials and resources delivered to your inbox.

No spam. Unsubscribe anytime.

3D Parallax Hero Section | HTML CSS JS | MetaSkillGroup