Make this Image Turbulence Reveal Effect on Scroll with Elementor

 

Want to get this as ready made template with just 1 CLICK INSTALL?

I want it as Ready Template

 

Code Snippet for Image Turbulence Reveal Effect:

<style>
body{
    --smooth-scroll: true;
    --fallback-circle: true;
}
[class^='mdw-turbulence-effect'],
[class*=' mdw-turbulence-effect']{
    --text-gap: 20px;
}
[class^='mdw-turbulence-effect'].anim .elementor-widget-heading,
[class*=' mdw-turbulence-effect'].anim .elementor-widget-heading,
[class^='mdw-turbulence-effect'].anim .elementor-widget-image svg,
[class*=' mdw-turbulence-effect'].anim .elementor-widget-image svg{
    transition: all 1s cubic-bezier(0,.33,.07,1.03);
}
[class^='mdw-turbulence-effect'] .elementor-widget-heading,
[class*=' mdw-turbulence-effect'] .elementor-widget-heading{
    opacity: 0;
    white-space: nowrap;
    max-width: unset !important;
    display: flex;
    justify-content: center;
}
[class^='mdw-turbulence-effect'] .elementor-widget-heading.show,
[class*=' mdw-turbulence-effect'] .elementor-widget-heading.show,
html.elementor-html [class^='mdw-turbulence-effect'] .elementor-widget-heading,
html.elementor-html [class*=' mdw-turbulence-effect'] .elementor-widget-heading{
    opacity: 1;
}
[class^='mdw-turbulence-effect'] p,
[class*=' mdw-turbulence-effect'] p{
    margin-bottom: 0;
}
[class^='mdw-turbulence-effect'] .elementor-widget-image svg,
[class*=' mdw-turbulence-effect'] .elementor-widget-image svg{
    position: absolute;
    left: 0;
    top: unset;
}
[class^='mdw-turbulence-effect'] .elementor-widget-image.eye image,
[class*=' mdw-turbulence-effect'] .elementor-widget-image.eye image{
    transform: none !important;
}
[class^='mdw-turbulence-effect'] .elementor-widget-image.eye.blur g,
[class*=' mdw-turbulence-effect'] .elementor-widget-image.eye.blur g{
    transform: scale(0.95);
    transform-origin: center;
}
[class^='mdw-turbulence-effect'] .elementor-widget-image.eye.blur image,
[class*=' mdw-turbulence-effect'] .elementor-widget-image.eye.blur image{
    transform: scale(1.05) !important;
}
[class^='mdw-turbulence-effect'] .elementor-widget-image img,
[class*=' mdw-turbulence-effect'] .elementor-widget-image img{
    opacity: 0;
}
html.elementor-html [class^='mdw-turbulence-effect'] .elementor-widget-image img,
html.elementor-html [class*=' mdw-turbulence-effect'] .elementor-widget-image img{
    opacity: 1;
}
[class^='mdw-turbulence-effect'] .elementor-widget-text-editor,
[class*=' mdw-turbulence-effect'] .elementor-widget-text-editor{
    max-width: var(--container-widget-width, 100%) !important;
}

@media (max-width:767px){
[class^='mdw-turbulence-effect'],
[class*=' mdw-turbulence-effect']{
    --text-gap: 10px;
}
[class^='mdw-turbulence-effect'] .elementor-widget-heading,
[class*=' mdw-turbulence-effect'] .elementor-widget-heading,
[class^='mdw-turbulence-effect'] .elementor-widget-text-editor,
[class*=' mdw-turbulence-effect'] .elementor-widget-text-editor{
    position: static !important;
}
[class^='mdw-turbulence-effect'] .elementor-widget-heading,
[class*=' mdw-turbulence-effect'] .elementor-widget-heading{
    max-width: 100% !important;
}
}
</style>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script>
if(!MDWNonce110){
var MDWNonce110 = true
;(function($){

var selector = "[class^='mdw-turbulence-effect'], [class*=' mdw-turbulence-effect']",
    image = [],
    img = [],
    title1 = [],
    title2 = [],
    heading1 = [],
    heading2 = [],
    windowHeight,
    windowWidth,
    imgWidth = [],
    imgHeight = [],
    imgOffset = [],
    maxRadius = [],
    translate = [],
    type = [],
    brightness = { start: 0.8, end: 1.0 },
    scale = { start: 0.9, end: 1.0 },
    isSafari,
    fallbackCircle,
    previousWidth
        
function getValue(el, prop){ return getComputedStyle(el[0]).getPropertyValue(prop) }

function init(){
$(selector).each(function(i){
    var $this = $(this)
    image[i] = $this.find('.elementor-widget-image')
    img[i] = image[i].find('img')
    title1[i] = $this.find('.elementor-widget-heading').eq(0)
    title2[i] = $this.find('.elementor-widget-heading').eq(1)
    heading1[i] = title1[i].find('.elementor-heading-title')
    heading2[i] = title2[i].find('.elementor-heading-title')
    $('body').append('<div class="mdw-100vh" style="height: 100vh;display: none;"></div>')
    isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
    fallbackCircle = getValue($('body'),'--fallback-circle') && getValue($('body'),'--fallback-circle') == 'true'
})
}

function setValues(){

windowHeight = $('.mdw-100vh').height()
windowWidth = $(window).width()

$(selector).each(function(i){
    var $this = $(this)
    
    imgWidth[i] = img[i].width()
    imgHeight[i] = img[i].height()
    maxRadius[i] = Math.sqrt(Math.pow(imgWidth[i]/2,2)+Math.pow(imgHeight[i]/2,2))+10
    if(isSafari && !fallbackCircle && maxRadius[i] > 850) maxRadius[i] = 850
})
}

function setSVG(){
$(selector).each(function(i){
    var $this = $(this),
    imgNaturalWidth = img[i][0].naturalWidth,
    imgNaturalHeight = img[i][0].naturalHeight,
    imgContainer =  image[i].find('.elementor-widget-container'),
    imgSrcset = img[i].attr('srcset').split(' '),
    imgUrl = imgSrcset[imgSrcset.length - 2],
    className = $this.attr('class'),
    classNameIndex = className.indexOf('mdw-turbulence-effect'),
    shortClass = className.substring(classNameIndex, className.indexOf(' ',classNameIndex)),
    values = shortClass.split('-'),
    blurHTML = shortClass.search('blur') == -1 || windowWidth < 768 || isSafari ? '' : '<feGaussianBlur in="displacement" stdDeviation="10"></feGaussianBlur>',
    shapeHTML = `<circle cx="50%" cy="50%" fill="white" class="mask" style="filter: url(#MDWFilter${i+1});"></circle>`,
    eyeClass = '',
    effectResolution = 0.03,
    effectArea = 50,
    effectOctave = 3,
    effectHTML,
    svgHTML
    
    values.forEach(function(value, index){
        if(value=='resolution' && values[index+1] && !isNaN(values[index+1])){ effectResolution = parseFloat(values[index+1])*0.003 }
        if(value=='area' && values[index+1] && !isNaN(values[index+1])){ effectArea = parseFloat(values[index+1])*5 }
    })
    
    if(effectArea > 100) effectOctave = 1
    
    if(blurHTML){
        image[i].addClass('blur')
        effectResolution = 0.01
        effectArea = 150
        effectOctave = 3
    }
    
    type[i] = 'circle'
    if(shortClass.search('eye') != -1){
        type[i] = 'eye'
        image[i].addClass('eye')
        effectResolution = 0.06
        if(blurHTML) effectResolution = 0
        effectArea = 50
        shapeHTML = `<path d="M 0 ${imgHeight[i]/2} Q ${imgWidth[i]/2} ${3*imgHeight[i]/2 - 2*12} ${imgWidth[i]} ${imgHeight[i]/2} Q ${imgWidth[i]/2} ${2*12 - imgHeight[i]/2} 0 ${imgHeight[i]/2}" fill="white" class="mask" style="filter: url(#MDWFilter${i+1});"></path>`
    }
    
    if( fallbackCircle && (windowWidth < 768 || isSafari) ){
        effectHTML = ''
    }else{
        effectHTML = 
        `<defs>
            <filter id="MDWFilter${i+1}">
                <feTurbulence type="fractalNoise" baseFrequency="${effectResolution}" numOctaves="${effectOctave}" result="noise"></feTurbulence>
                
                <feDisplacementMap in="SourceGraphic" in2="noise" scale="${effectArea}" xChannelSelector="R" yChannelSelector="G"></feDisplacementMap>
                ${blurHTML}
            </filter>
            <mask id="MDWCircle${i+1}">
                ${shapeHTML}
            </mask>
        </defs>`
    }
    
    svgHTML = 
    `<svg width="${imgWidth[i]}" height="${imgHeight[i]}" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 ${imgWidth[i]} ${imgHeight[i]}">
        ${effectHTML}
        <g mask="url(#MDWCircle${i+1})">
            <image href="${imgUrl}" width="${imgWidth[i]}" height="${imgHeight[i]}" style="transform: scale(${scale.start}); transform-origin: center center; filter: brightness(${brightness.start});" preserveAspectRatio="xMidYMid slice"></image>
        </g>
    </svg>`
    
    imgContainer.find('svg').remove()
    imgContainer.append(svgHTML)
})
}

function getOffset(el){
    var left = 0, top = 0
    do{
      if (!isNaN(el.offsetLeft)) left += el.offsetLeft
      if (!isNaN(el.offsetTop)) top += el.offsetTop
    }while(el = el.offsetParent)
    return { top, left }
}

function setInitTranslate(){

var scrollTop = $(window).scrollTop()
    
$(selector).each(function(i){
    var $this = $(this),
    H1Offset = getOffset(heading1[i][0]),
    H2Offset = getOffset(heading2[i][0]),
    imgOffset = getOffset(img[i][0]),
    textGap = !isNaN(parseFloat(getValue($this, '--text-gap'))) ? parseFloat(getValue($this, '--text-gap')) : 20,
    T1X,T1Y,T2X,T2Y
    
    T1X = - H1Offset.left + (windowWidth - heading1[i].width() - heading2[i].width() - textGap) / 2
    T1Y = imgOffset.top - H1Offset.top + (imgHeight[i] - heading1[i].height())/2
    T2X = - H2Offset.left + (windowWidth + heading1[i].width() - heading2[i].width() + textGap) / 2
    T2Y = imgOffset.top - H2Offset.top + (imgHeight[i] - heading2[i].height())/2
    
    translate[i] = {T1X,T1Y,T2X,T2Y}
})
}

function getScrollValue(imgOffset, imgHeight, startPercent, endPercent, inverse= false){
    var start = startPercent/100*windowHeight,
    end = endPercent/100*windowHeight,
    scrollValue = (imgOffset.top+imgHeight/2-start)/(end - start),
    value = Math.max(Math.min(scrollValue,1),0)
        
    if(inverse) value = 1 - value
    return value
}

function revealImage(startPercent){
    
var imgStartPercent = 90,
    imgEndPercent = 60

$(selector).each(function(i){
    
    imgOffset[i] = img[i][0].getBoundingClientRect()
    
    var svg = image[i].find('svg'),
    svgCircle = svg.find('circle'),
    svgPath = svg.find('path'),
    svgGroup = svg.find('g'),
    svgImage = svg.find('image'),
    revealAmount = getScrollValue(imgOffset[i], imgHeight[i], imgStartPercent, imgEndPercent),
    currentBrightness = brightness.start + (brightness.end - brightness.start)*revealAmount,
    currentScale = scale.start + (scale.end - scale.start)*revealAmount,
    curretRadius = maxRadius[i]*revealAmount
    
    svgImage.css({
        'filter': `brightness(${currentBrightness})`,
        'transform': `scale(${currentScale})`
    })
    
    if( fallbackCircle && (windowWidth < 768 || isSafari) ){
        if( type[i] == 'circle' ) {
            svg.css('clip-path', `circle(${curretRadius}px at 50% 50%)`)
        }else{
            svg.css('clip-path', `ellipse(50% ${revealAmount*50}% at 50% 50%)`)
        }
    }else{
        if( type[i] == 'circle' ) {
            svgCircle.attr('r', curretRadius)    
        }else{
            svgGroup.attr('mask', `url(#MDWCircle${i+1})`)
            svgPath.attr('d', `M 0 ${imgHeight[i]/2} Q ${imgWidth[i]/2} ${imgHeight[i]/2 + (imgHeight[i] - 2*12)*revealAmount} ${imgWidth[i]} ${imgHeight[i]/2} Q ${imgWidth[i]/2} ${imgHeight[i]/2 + (2*12 - imgHeight[i])*revealAmount} 0 ${imgHeight[i]/2}`)
        }
    }
})
}

function moveText(startPercent){
    
var titleStartPercent = 90,
    titleEndPercent = 50

$(selector).each(function(i){
    
    var $this = $(this),
    translateAmount = getScrollValue(imgOffset[i], imgHeight[i], titleStartPercent, titleEndPercent, true),
    T1T = {x: translate[i].T1X*translateAmount, y: translate[i].T1Y*translateAmount}
    T2T = {x: translate[i].T2X*translateAmount, y: translate[i].T2Y*translateAmount}
    
    title1[i].css('transform', `translate(${T1T.x}px, ${T1T.y}px)`)
    title2[i].css('transform', `translate(${T2T.x}px, ${T2T.y}px)`)
    title1[i].addClass('show')
    title2[i].addClass('show')
    setTimeout(function(){ $this.addClass('anim') }, 50)

})
}

function scrollAnimation(){
    revealImage()
    moveText()
}

function runAnimation(e){
    if(e.type=='load') init()
    setValues()
    setSVG()
    setInitTranslate()
    scrollAnimation()
}

$(document).ready(init)
$(window).on('scroll', scrollAnimation)
$(window).on('load resize', function(e){
    if(e.type=='resize' && $(window).width() < 768 && $(window).width() == previousWidth) return
    runAnimation(e)
    setTimeout(function(){ runAnimation(e) }, 100)
    setTimeout(function(){ runAnimation(e) }, 500)
    setTimeout(function(){ runAnimation(e) }, 1000)
    previousWidth = $(window).width()
})

})(jQuery)
}
</script>

<!-- Smooth Scroll with Lenis JS -->

<style>
html.lenis, html.lenis body {
  height: auto;
}
.lenis.lenis-smooth {
  scroll-behavior: auto !important;
}
.lenis.lenis-smooth [data-lenis-prevent] {
  overscroll-behavior: contain;
}
.lenis.lenis-stopped {
  overflow: hidden;
}
.lenis.lenis-smooth iframe {
  pointer-events: none;
}
</style>
<script src="https://unpkg.com/lenis@1.1.11/dist/lenis.min.js"></script> 
<script>
$(document).ready(function(){

var smoothScroll = getComputedStyle(document.body).getPropertyValue('--smooth-scroll'),
    smoothScroll = smoothScroll && smoothScroll == 'true'

if(smoothScroll){
    var lenis = new Lenis()
    function raf(time) {
      lenis.raf(time)
      requestAnimationFrame(raf)
    }
    requestAnimationFrame(raf)
}
})
</script>