Move a radial gradient fragment on mouse move event with continuous easing

Hi all,
I want to recreate this background effect:

I find it a little difficult to find the needed js code on their website, but it looks like it was made with three.js library.

I am still very new to three.js but I’m very exciting to learn more.

This is what I came up with so far with some help from ChatGPT CodePen Project

In my code I have created a square plane geometry and added a shader fragment so it will look like a radial-gradient. On events for mousemove I move the radial gradient around the canvas (Opposite to the cursor position).

My issue now is with the movement and easing of the radial gradient since it is not continuous. It first animates, when I stop moving my cursor for a second etc. (I have also tried with tween js library) This is my code for the mouse move events:

// Create a function to update the square's position and material properties
function updateSquare(event) {
    const mouseX = (event.clientX / window.innerWidth) * 2 - 1;
    const mouseY = -(event.clientY / window.innerHeight) * 2 + 1;

    // Update the shader's mouse position with easing
    squareMaterial.uniforms.uMouse.value.x += (-mouseX * 0.5 - squareMaterial.uniforms.uMouse.value.x) * 0.1;
    squareMaterial.uniforms.uMouse.value.y += (-mouseY * 0.5 - squareMaterial.uniforms.uMouse.value.y) * 0.1;

// Handle mouse movement to move the square
window.addEventListener('mousemove', updateSquare);

Also I am not sure if I have setup my camera correct, but these settings seems to work for me

// Create a red square geometry
const squareGeometry = new THREE.PlaneGeometry(8, 8);

It feels like the geometry (square) and the material (radial gradient) are not linked because if I move the square position it will not move the material. Before I had to move both the geometry + material, but I guess since I use (8, 8) for the plane geometry it is big enough to fill the whole canvas out so I only need to move the material.

  • I haven’t been able to use the circle geometry (Maybe it is better to use?). And I need a 1:1 square or else my radial gradient will be stretched.

I guess this effect could be recreated with much simpler js and css code than using three.js but I wanted to have a look on the library and how the source effect was created.

Best Regards Shane

To move the background continuously, you need to move it in the animation loop; and the mousemove handler should only record the target position. Something like this:

var mouseX=0, mouseY=0;

function updateSquare(event) {
    mouseX = (event.clientX / window.innerWidth) * 2 - 1;
    mouseY = -(event.clientY / window.innerHeight) * 2 + 1;

window.addEventListener('mousemove', updateSquare);

const animate = () => {
    squareMaterial.uniforms.uMouse.value.x += (-mouseX * 0.5 - squareMaterial.uniforms.uMouse.value.x) * 0.005;
    squareMaterial.uniforms.uMouse.value.y += (-mouseY * 0.5 - squareMaterial.uniforms.uMouse.value.y) * 0.005;

    renderer.render(scene, camera);

However, if you are curious about a solution without any custom shaders, here is what I came up with:



Hi PavelBoytchev,

Thank you for the help and your great example!

I managed to get it to work as I wanted.

I like the cursor animation in your solution but I don’t think it will work together because the canvas will be a background element going behind every other elements on the website so the cursor effect will do the same I suppose.
Or maybe I can create it in another canvas going on top of everything with just the cursor effect. But that seems too much.

Thanks a lot! :slight_smile:

1 Like