Get the finished version

Want your website to look more impressive? Import all my designs including this one:

Build it manually from scratch:

All materials:

Download Images:

Classes:

np-hero

cs-peak

np-rock-before

np-rock-after

CSS:

				
					<style>
.cs-title .elementor-heading-title {
  background-image: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.98) 38%,
    rgba(255, 255, 255, 0.62) 80%,
    rgba(255, 255, 255, 0.38) 100%
  );

  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;

  white-space: nowrap;
  line-height: 0.95;
  padding-bottom: 0.06em;
}

.np-hero {
  position: relative !important;
  overflow: hidden !important;
}

.np-hero > .elementor-widget-html {
  position: absolute !important;
  top: 0 !important;
  left: 0 !important;
  width: 0 !important;
  height: 0 !important;
  margin: 0 !important;
  padding: 0 !important;
  overflow: hidden !important;
  pointer-events: none !important;
  z-index: 0 !important;
}

.np-hero .cs-peak {
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  margin: 0 !important;
  padding: 0 !important;
  overflow: hidden !important;
  z-index: 3 !important;
  display: block !important;
}

.np-hero .np-rock-before,
.np-hero .np-rock-after {
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  margin: 0 !important;
  padding: 0 !important;
  display: block !important;
  visibility: visible !important;
  opacity: 1 !important;
  overflow: hidden !important;
  pointer-events: none !important;
}

.np-hero .np-rock-before {
  z-index: 1 !important;
}

.np-hero .np-rock-after {
  z-index: 2 !important;
}

.np-hero .np-rock-before > .elementor-widget-container,
.np-hero .np-rock-after > .elementor-widget-container {
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  margin: 0 !important;
  padding: 0 !important;
  display: block !important;
}

.np-hero .np-rock-before figure,
.np-hero .np-rock-after figure,
.np-hero .np-rock-before .elementor-image,
.np-hero .np-rock-after .elementor-image {
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  margin: 0 !important;
  padding: 0 !important;
  display: block !important;
}

.np-hero .np-rock-before a,
.np-hero .np-rock-after a {
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  margin: 0 !important;
  padding: 0 !important;
  display: block !important;
}

.np-hero .np-rock-before img,
.np-hero .np-rock-after img {
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
  max-width: none !important;
  margin: 0 !important;
  padding: 0 !important;
  display: block !important;
  object-fit: cover !important;
  object-position: center center !important;
  background: transparent !important;
  visibility: visible !important;
  opacity: 1 !important;
}

.np-hero .np-rock-after {
  --np-x: -9999px;
  --np-y: -9999px;
  --np-r: 175px;
  --np-a: 0;

  -webkit-mask-repeat: no-repeat !important;
  mask-repeat: no-repeat !important;

  -webkit-mask-size: 100% 100% !important;
  mask-size: 100% 100% !important;

  -webkit-mask-image: radial-gradient(
    circle var(--np-r) at var(--np-x) var(--np-y),
    rgba(0, 0, 0, var(--np-a)) 0%,
    rgba(0, 0, 0, var(--np-a)) 72%,
    rgba(0, 0, 0, 0) 100%
  );

  mask-image: radial-gradient(
    circle var(--np-r) at var(--np-x) var(--np-y),
    rgba(0, 0, 0, var(--np-a)) 0%,
    rgba(0, 0, 0, var(--np-a)) 72%,
    rgba(0, 0, 0, 0) 100%
  );

  will-change: -webkit-mask-image, mask-image;
}

@media (hover: none) {
  .np-hero .np-rock-after {
    --np-a: 0 !important;
  }
}
</style>

<script>
(function () {
  function setup(hero) {
    if (!hero) return false;
    if (hero.dataset.npRevealReady === '1') return true;

    var peak = hero.querySelector('.cs-peak');

    if (!peak) return false;

    var before = peak.querySelector('.np-rock-before');
    var after = peak.querySelector('.np-rock-after');

    if (!before || !after) return false;

    hero.dataset.npRevealReady = '1';

    if (
      !window.matchMedia ||
      !window.matchMedia('(hover: hover)').matches
    ) {
      return true;
    }

    var reduced = window.matchMedia(
      '(prefers-reduced-motion: reduce)'
    ).matches;

    var rect = null;
    var dirty = true;
    var running = false;

    var tx = -9999;
    var ty = -9999;
    var cx = -9999;
    var cy = -9999;

    var alpha = 0;
    var targetAlpha = 0;
    var seeded = false;

    function radius() {
      var width = window.innerWidth || 1440;

      return width < 768
        ? 98
        : width < 1025
          ? 133
          : 175;
    }

    var revealRadius = radius();

    after.style.setProperty(
      '--np-r',
      revealRadius + 'px'
    );

    function measure() {
      rect = peak.getBoundingClientRect();
      dirty = false;
    }

    function mark() {
      dirty = true;
    }

    function apply() {
      after.style.setProperty(
        '--np-x',
        cx.toFixed(1) + 'px'
      );

      after.style.setProperty(
        '--np-y',
        cy.toFixed(1) + 'px'
      );

      after.style.setProperty(
        '--np-a',
        alpha.toFixed(3)
      );
    }

    function frame() {
      var easing = reduced ? 1 : 0.18;
      var busy = false;

      var nextX = cx + (tx - cx) * easing;
      var nextY = cy + (ty - cy) * easing;

      if (
        Math.abs(nextX - cx) > 0.1 ||
        Math.abs(nextY - cy) > 0.1
      ) {
        busy = true;
      }

      cx = nextX;
      cy = nextY;

      var alphaDifference = targetAlpha - alpha;

      if (Math.abs(alphaDifference) > 0.004) {
        alpha += alphaDifference * (reduced ? 1 : 0.2);
        busy = true;
      } else {
        alpha = targetAlpha;
      }

      apply();

      if (busy) {
        requestAnimationFrame(frame);
      } else {
        running = false;
      }
    }

    function kick() {
      if (!running) {
        running = true;
        requestAnimationFrame(frame);
      }
    }

    peak.addEventListener(
      'pointermove',
      function (event) {
        if (event.pointerType === 'touch') return;

        if (dirty || !rect) {
          measure();
        }

        if (!rect || !rect.width) return;

        tx = event.clientX - rect.left;
        ty = event.clientY - rect.top;

        if (!seeded) {
          seeded = true;
          cx = tx;
          cy = ty;
        }

        targetAlpha = 1;
        kick();
      },
      { passive: true }
    );

    function hideReveal() {
      targetAlpha = 0;
      seeded = false;
      kick();
    }

    peak.addEventListener(
      'pointerleave',
      hideReveal,
      { passive: true }
    );

    peak.addEventListener(
      'pointercancel',
      hideReveal,
      { passive: true }
    );

    hero.addEventListener(
      'pointerleave',
      hideReveal,
      { passive: true }
    );

    window.addEventListener(
      'resize',
      function () {
        revealRadius = radius();

        after.style.setProperty(
          '--np-r',
          revealRadius + 'px'
        );

        mark();
      },
      { passive: true }
    );

    window.addEventListener(
      'scroll',
      mark,
      { passive: true }
    );

    if (window.ResizeObserver) {
      try {
        new ResizeObserver(mark).observe(peak);
      } catch (error) {}
    }

    return true;
  }

  function init() {
    var heroes = document.querySelectorAll('.np-hero');
    var ready = heroes.length > 0;

    for (var i = 0; i < heroes.length; i++) {
      if (!setup(heroes[i])) {
        ready = false;
      }
    }

    return ready;
  }

  var tries = 0;

  (function poll() {
    if (init()) return;
    if (++tries > 240) return;

    requestAnimationFrame(poll);
  })();

  if (document.readyState === 'loading') {
    document.addEventListener(
      'DOMContentLoaded',
      init,
      { once: true }
    );
  }

  window.addEventListener(
    'load',
    init,
    { once: true }
  );

  if (window.jQuery) {
    jQuery(window).on(
      'elementor/frontend/init',
      init
    );
  }
})();
</script>
				
			

Unlock your best work yet

Launch premium websites and save hours on every project.

All Access — 12 Months

One-time payment. Access for 12 months. Instant access. 

$199

$259

All access — Lifetime

Most people choose

One-time payment. Never pay again.
Instant access.

$249

$459

Unlock your best work yet

Launch premium websites and save hours on every project.

All Access — 12 Months

One-time payment. Access for 12 months. Instant access. 

$199

$259

All access — Lifetime

Most people choose

One-time payment. Never pay again.
Instant access.

$249

$459