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.
- Hero Section
- hero-section
- 3d
- parallax
- landing-page
- mockup
- saas
- css-animation
Features Included
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
- Google Fonts — Plus Jakarta Sans https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap
Already linked inside the component's files — no extra setup needed.
Desktop Preview

HTML
html1<!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
css1/* 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
javascript1const 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
Found this useful?

Written by