Hover over the image to see the liquid effect change when the mouse moves in

Can anyone assist me in achieving an image change with a liquid effect similar to the one demonstrated here?

I have a basic image container and I am looking to swap out the image (to another image) on mouseover, implementing this effect, and then return it back to its original state on mouseout with the same effect.

const avatarQuantumBreak = document.querySelector(".avatar_quantum_break");
const avatar = document.querySelector(".avatar");

avatarQuantumBreak.style.opacity = "0";

let hover = () => avatarQuantumBreak.style.opacity = "1";
let normal = () => avatarQuantumBreak.style.opacity = "0";

avatar.onmouseover = () => hover();
avatar.onmouseout = () => normal();
html , body {
  height:100%;
}

.avatar {
  position: relative;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  height: 195px;
}
.avatar_simple,
.avatar_quantum_break {
  position: absolute;
  display: block;
  text-align:center;
  transition: opacity 1s ease-out;
}
.avatar .avatar_simple img,
.avatar .avatar_quantum_break img {
  border-radius: 50%;
  display: inline-block;
  width: 86%;
  height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.0.2/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js"></script>


<div class=avatar>
    <span class=avatar_simple>
        <img src="https://pixel.nymag.com/imgs/fashion/daily/2014/05/27/27-amber-heard.w330.h330.jpg">
    </span>
    <span class=avatar_quantum_break>
        <img src="https://pixel.nymag.com/imgs/daily/vulture/2016/05/31/31-amber-heard.w330.h330.jpg">
    </span>
</div>

The function responsible for triggering the liquid animation is as follows:

transitionNext() {
    TweenMax.to(this.mat.uniforms.dispPower, 2.5, {
      value: 1,
      ease: Expo.easeInOut,
      onUpdate: this.render,
      onComplete: () => {
        this.mat.uniforms.dispPower.value = 0.0
        this.changeTexture()
        this.render.bind(this)
        this.state.animating = false
      }
    })

I attempted to use this function without success.

Furthermore, I tried altering the images in line 15 of this Array, but that also did not resolve the issue.

this.images = [ //1
      'https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/bg1.jpg',
      'https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/bg2.jpg',
      'https://s3-us-west-2.amazonaws.com/s.cdpn.io/58281/bg3.jpg'
    ]

This function initializes the animation:

listeners() {
   window.addEventListener('wheel', this.nextSlide, { passive: true })
}

Function for transitioning to the next slide:

nextSlide() {
   if (this.state.animating) return

   this.state.animating = true

   this.transitionNext()

   this.data.current = this.data.current === this.data.total ? 0 : this.data.current + 1
this.data.next = this.data.current === this.data.total ? 0 : this.data.current + 1
}

Any assistance regarding this matter would be greatly appreciated.

Answer №1

Exciting fusion - where real-time visual effects meet the world of web development :)

The enchanting effect you see here is crafted with a GLSL shader (you can explore it in the example html code below) and I've sprinkled some comments to guide you through it

   // The following lines represent input data received by the GPU from JavaScript
    varying vec2 vUv; // UV coordinate of the current pixel
    uniform sampler2D texture1; // Image 1
    uniform sampler2D texture2; // Image 2
    uniform sampler2D disp; // Noise texture
    uniform float dispPower; // Progress of the effect
    uniform float intensity; // Scale of the effect

    void main() {
        vec2 uv = vUv;

        vec4 noise = texture2D(disp, uv); // Access noise texture
        vec2 noiseVec = vec2(noise.x, noise.y); // Extract red and green values

        // Calculate UV displacement
        vec2 distPos1 = uv + (noiseVec * intensity * dispPower); 
        vec2 distPos2 = uv + (noiseVec * -(intensity * (1.0 - dispPower)));

        // Sample images using the displaced UVs
        vec4 _texture1 = texture2D(texture1, distPos1); 
        vec4 _texture2 = texture2D(texture2, distPos2);

        // Blend both images based on the effect's progress and assign color to the output pixel
        gl_FragColor = mix(_texture1, _texture2, dispPower);
    }

This shader takes 3 textures as input: image1, image2, and a noise texture employed for UV distortion, producing a color value for each pixel frame during the transition effect processing directly on the GPU, applied across all pixels on the surface.

This technique is known as "Texture Distortion" or "UV Displacement," which involves adjusting UV coordinates utilizing the information stored in a noise texture.

If you're keen on diving into GLSL, a fantastic starting point would be

For GLSL reference material, check out

I also recommend exploring

Welcome to the enchanting realm of real-time visual effects!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can you identify this numerical category?

Can you identify this number type? console.log(0100); // output 64 console.log(050); // output 40 console.log(010); // output 8 In a hexadecimal system, it would be: 0100 = 256 050 = 80 010 = 16 ...

Top method in Angular 6 for verifying if a scrollable section has been scrolled to the very bottom

I am searching for a reliable solution in Angular 6 to determine whether a scrollable host component has reached its maximum scroll bottom. Despite my efforts, I have been unsuccessful in finding a functioning example of a function that can detect if a cu ...

In order to apply a filter express within an array, make sure to utilize variables that

In my Express endpoint, I have various variables that may or may not be present. Depending on the presence of these variables, I need to execute a filter function on an array and apply rules from the req.body. Is there a way to include if conditions withi ...

Why does the Google Places API consistently provide latitude and longitude values under varying variables each time?

I am completely baffled by this situation. Initially, the API was returning the Latitude and Longitude like this: (I believe it was in this format): place.geometry.location.y as Latitude place.geometry.location.z as Longitude Then it suddenly change ...

Iterate over Observable data, add to an array, and showcase all outcomes from the array in typescript

Is there a way to iterate through the data I've subscribed to as an Observable, store it in an array, and then display the entire dataset from the array rather than just page by page? Currently, my code only shows data from each individual "page" but ...

Activate a JavaScript mouse event outside of an element

https://jsfiddle.net/f8L300ug/3/ Attempting to create a drag-to-resize feature, inspired by the provided example. One challenge encountered is that when the mouse is released outside of the <body>, the mouseup event does not trigger as expected. Th ...

Ways to incorporate External JS and CSS files into Angular 5 (loading files with a delay)

I have encountered some challenges while attempting to import external JS and CSS files into my Angular 5 application. Below is the code snippet that I have tried so far: Component.ts : ngOnInit() { this.loadScript(); // also attempted with ...

Perform an additional HTTP request and utilize the response within the existing Observable

In my Angular 2 project, I am utilizing the http component to make API calls. The specific REST API I want to access returns a maximum of 100 Elements in one request. If more items exist, a hasMore flag is included in the response. To retrieve additional ...

Securing JSON-based RESTful services

I am in the process of developing a web application, where I have established a clear separation between my "frontend" server using Lighttpd to serve index.html and javascript. My frontend, powered by Backbone.js, is connected to my Node.js backend webser ...

What is the best approach for filtering a nested array in this scenario?

Here is the response I am getting: let m = [ { name: 'Summary', subListExpanded: false, subList: [ ] }, { name: 'Upload', subListExpanded: false, subList: [ ...

Node.js encountered an error: Module 'mongoose' not found

C:\Users\Alexa\Desktop\musicapp\Bots\Soul Bot>node bot.js Node.js Error: Missing module 'mongoose' at Function._resolveFilename (module.js:334:11) at Function._load (module.js:279:25) at Module.requir ...

What is the best way to utilize a variable declared in a JavaScript file within an HTML document?

Here is the content of my JavaScript file: var moment = require("moment") var structuredDate = moment(Date()).format("LLLL") I am trying to dynamically update a <div> element in my HTML with the date value. This is what I attem ...

Using d3 to showcase pictures sourced from a csv file

Having recently embarked on a journey to learn javascript, d3, and the polymer project, I am facing a challenge that I hope to get some guidance on. After successfully parsing a csv file containing image information and creating an array specifically for ...

How can I transform a Firestore collection into an array?

I'm struggling with converting the data retrieved from Firestore into an array that can be used for a chart.js graph. Retrieving Data from Firestore fetchData(){ //Get data this.updatesCollection = this.afs.collection(pathStats); this. ...

Ways to identify when a specific react component has been clicked

Currently working on developing a klondike game with 4 empty stacks at the start of the game. The initial page layout resembles the first image provided in the link. I am facing an issue where I cannot determine which component was clicked when clicking on ...

Error: The variable "details.date.getTime" is not defined and cannot be accessed

Currently, I am utilizing https://github.com/zo0r/react-native-push-notification to display notifications. Specifically, I am using scheduled notifications with datetimepicker. Previously, I have successfully used this in another project without any errors ...

Tips for displaying a popup modal when a link is clicked with ajax technology

I am facing an issue with my popup modal. When a user clicks on a link, the modal appears but without any content. I am new to ajax and feeling a bit confused about what steps to take next. Below is the HTML code snippet: <div class="modal fade&quo ...

The creation of transparent objects in THREE.js allows for a dynamic display of overlaid objects in the

Greetings, I am interested in creating a three.js room where the walls behind which objects are located (from the perspective of the camera) will become transparent with 50% opacity as I rotate the room. Allow me to elaborate: Visualize a scenario whe ...

The Handsontable namespace does not include the _editors module in its exports

While following the documentation, I encountered an error when trying to integrate handsOnTable with my Vue 2 project using npm. The build process failed with the following message: ERROR in /node_modules/@handsontable/vue/types.d.ts(56,73): 56:73 Namesp ...

Clearly state the action of the form

I have utilized html, JavaScript, CSS, and JQuery to create a website template. Within this template, there is a file called contact.js that contains the ajax code for handling forms: $(function() { submitSuccess: function($form, event) { ...