back

Back

Point

new

October 31, 2025

Point - new Background

How to implement:

With tailwind installed in your project tutorial, implement these tailwind classes in your parent div where it will reflect the background.

Code:

<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Ghost Mouse 3 - Background Interativo</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    body {
      margin: 0;
      padding: 0;
      overflow: hidden;
      background: #000;
    }
  </style>
</head>
<body>
  <div id="container" touch-action="none"></div>
  <!-- Three.js via CDN - usando versão r88 compatível -->
  <script>
    function loadThreeJS() {
      return new Promise(function(resolve, reject) {
        if (typeof THREE !== 'undefined') {
          resolve();
          return;
        }
        
        var script = document.createElement('script');
        script.src = 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r88/three.min.js';
        script.async = true;
        
        script.onload = function() {
          var checkInterval = setInterval(function() {
            if (typeof THREE !== 'undefined') {
              clearInterval(checkInterval);
              resolve();
            }
          }, 10);
          
          setTimeout(function() {
            clearInterval(checkInterval);
            if (typeof THREE === 'undefined') {
              loadThreeJSAlternative().then(resolve).catch(reject);
            }
          }, 5000);
        };
        
        script.onerror = function() {
          console.warn('CDN principal falhou, tentando CDN alternativo...');
          loadThreeJSAlternative().then(resolve).catch(reject);
        };
        
        document.head.appendChild(script);
      });
    }
    
    function loadThreeJSAlternative() {
      return new Promise(function(resolve, reject) {
        var script = document.createElement('script');
        script.src = 'https://unpkg.com/three@0.88.0/build/three.min.js';
        script.async = true;
        
        script.onload = function() {
          var checkInterval = setInterval(function() {
            if (typeof THREE !== 'undefined') {
              clearInterval(checkInterval);
              resolve();
            }
          }, 10);
          
          setTimeout(function() {
            clearInterval(checkInterval);
            if (typeof THREE === 'undefined') {
              reject(new Error('Three.js não pôde ser carregado'));
            }
          }, 5000);
        };
        
        script.onerror = function() {
          reject(new Error('Todos os CDNs falharam'));
        };
        
        document.head.appendChild(script);
      });
    }
    
    window.threeJSLoadPromise = loadThreeJS();
  </script>

  <script id="vertexShader" type="x-shader/x-vertex">
    void main() {
      gl_Position = vec4(position, 1.0);
    }
  </script>

  <!-- Fragment Shader -->
  <script id="fragmentShader" type="x-shader/x-fragment">
    uniform vec2 u_resolution;
    uniform vec2 u_mouse;
    uniform float u_time;
    uniform sampler2D u_noise;
    uniform sampler2D u_buffer;
    uniform bool u_renderpass;
    
    const float blurMultiplier = 0.95;
    const float circleSize = .25;
    const float blurStrength = .98;
    const float threshold = .5;
    const float scale = 4.;
    
    #define _fract true
    
    #define PI 3.141592653589793
    #define TAU 6.283185307179586

    vec2 hash2(vec2 p) {
      vec2 o = texture2D(u_noise, (p+0.5)/256.0, -100.0).xy;
      return o;
    }
    
    vec3 hsb2rgb(in vec3 c) {
      vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0), 6.0)-3.0)-1.0, 0.0, 1.0);
      rgb = rgb*rgb*(3.0-2.0*rgb);
      return c.z * mix(vec3(1.0), rgb, c.y);
    }
    
    vec3 domain(vec2 z) {
      return vec3(hsb2rgb(vec3(atan(z.y,z.x)/TAU,1.,1.)));
    }
    
    vec3 colour(vec2 z) {
      return domain(z);
    }

    #define pow2(x) (x * x)

    const int samples = 8;
    const float sigma = float(samples) * 0.25;

    float gaussian(vec2 i) {
      return 1.0 / (2.0 * PI * pow2(sigma)) * exp(-((pow2(i.x) + pow2(i.y)) / (2.0 * pow2(sigma))));
    }

    vec3 hash33(vec3 p) {
      float n = sin(dot(p, vec3(7, 157, 113)));    
      return fract(vec3(2097152, 262144, 32768)*n); 
    }

    vec3 blur(sampler2D sp, vec2 uv, vec2 scale) {
      vec3 col = vec3(0.0);
      float accum = 0.0;
      float weight;
      vec2 offset;
      
      for (int x = -samples / 2; x < samples / 2; ++x) {
        for (int y = -samples / 2; y < samples / 2; ++y) {
          offset = vec2(x, y);
          weight = gaussian(offset);
          col += texture2D(sp, uv + scale * offset).rgb * weight;
          accum += weight;
        }
      }
      
      return col / accum;
    }
    
    void main() {
      vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / u_resolution.y;
      uv *= scale;
      vec2 mouse = u_mouse * scale;
      
      vec2 ps = vec2(1.0) / u_resolution.xy;
      vec2 sample = gl_FragCoord.xy / u_resolution.xy;
      vec2 o = mouse*.2+vec2(.65, .5);
      float d = .98;
      sample = d * (sample - o);
      sample += o;
      sample += vec2(sin((u_time+uv.y * .5)*10.)*.001, -.00);
      
      vec3 fragcolour;
      vec4 tex;
      
      if(u_renderpass) {
        tex = vec4(blur(u_buffer, sample, ps*blurStrength) * blurMultiplier, 1.);
        float df = length(mouse - uv);
        fragcolour = vec3(smoothstep(circleSize, 0., df));
      } else {
        tex = texture2D(u_buffer, sample, 2.) * .98;
        tex = vec4(
          smoothstep(0.0, threshold - fwidth(tex.x), tex.x),
          smoothstep(0.2, threshold - fwidth(tex.y) + .2, tex.y),
          smoothstep(-0.05, threshold - fwidth(tex.z) - .2, tex.z),
          1.);
        vec3 n = hash33(vec3(uv, u_time*.1));
        tex.rgb += n * .2 - .1;
      }

      gl_FragColor = vec4(fragcolour,1.0);
      gl_FragColor += tex;
    }
  </script>

  <!-- JavaScript inline - toda a lógica em um único arquivo -->
  <script>
    let retryCount = 0;
    const MAX_RETRIES = 50; // Máximo de 5 segundos (50 * 100ms)
    
    function initGhostMouse() {
      if (typeof THREE === 'undefined') {
        retryCount++;
        if (retryCount < MAX_RETRIES) {
          setTimeout(initGhostMouse, 100);
        } else {
          console.error('Three.js não conseguiu carregar. Verifique sua conexão ou o CDN.');
        }
        return;
      }
      
      retryCount = 0;

      (function() {
        'use strict';

        // ==========================================
        // Ghost Mouse 3 - Background Interativo
        // Tudo inline para fácil integração
        // ==========================================

        let container;
        let camera, scene, renderer;
        let uniforms;
        let divisor = 1 / 10;
        let newmouse = { x: 0, y: 0 };
        let texture, rtTexture, rtTexture2;
        let animationId;

        let loader = new THREE.TextureLoader();
        loader.setCrossOrigin("anonymous");
        loader.load(
          'https://s3-us-west-2.amazonaws.com/s.cdpn.io/982762/noise.png',
          function do_something_with_texture(tex) {
            texture = tex;
            texture.wrapS = THREE.RepeatWrapping;
            texture.wrapT = THREE.RepeatWrapping;
            texture.minFilter = THREE.LinearFilter;
            init();
            animate();
          }
        );

      function init() {
        container = document.getElementById('container');

        camera = new THREE.Camera();
        camera.position.z = 1;

        scene = new THREE.Scene();
        var geometry = new THREE.PlaneBufferGeometry(2, 2);

        rtTexture = new THREE.WebGLRenderTarget(window.innerWidth * 0.2, window.innerHeight * 0.2);
        rtTexture2 = new THREE.WebGLRenderTarget(window.innerWidth * 0.2, window.innerHeight * 0.2);

        uniforms = {
          u_time: { type: "f", value: 1.0 },
          u_resolution: { type: "v2", value: new THREE.Vector2() },
          u_noise: { type: "t", value: texture },
          u_buffer: { type: "t", value: rtTexture.texture },
          u_mouse: { type: "v2", value: new THREE.Vector2() },
          u_renderpass: { type: 'b', value: false }
        };

        var material = new THREE.ShaderMaterial({
          uniforms: uniforms,
          vertexShader: document.getElementById('vertexShader').textContent,
          fragmentShader: document.getElementById('fragmentShader').textContent
        });

        material.extensions.derivatives = true;

        var mesh = new THREE.Mesh(geometry, material);
        scene.add(mesh);

        renderer = new THREE.WebGLRenderer();
        renderer.setPixelRatio(window.devicePixelRatio);

        container.appendChild(renderer.domElement);

        onWindowResize();
        window.addEventListener('resize', onWindowResize, false);

        document.addEventListener('pointermove', (e) => {
          let ratio = window.innerHeight / window.innerWidth;
          newmouse.x = (e.pageX - window.innerWidth / 2) / window.innerWidth / ratio;
          newmouse.y = (e.pageY - window.innerHeight / 2) / window.innerHeight * -1;
          e.preventDefault();
        });
      }

      function onWindowResize(event) {
        renderer.setSize(window.innerWidth, window.innerHeight);
        uniforms.u_resolution.value.x = renderer.domElement.width;
        uniforms.u_resolution.value.y = renderer.domElement.height;

        rtTexture = new THREE.WebGLRenderTarget(window.innerWidth * 0.2, window.innerHeight * 0.2);
        rtTexture2 = new THREE.WebGLRenderTarget(window.innerWidth * 0.2, window.innerHeight * 0.2);
      }

      let then = 0;
      function renderTexture(delta) {
        let odims = uniforms.u_resolution.value.clone();
        uniforms.u_resolution.value.x = window.innerWidth * 0.2;
        uniforms.u_resolution.value.y = window.innerHeight * 0.2;

        uniforms.u_buffer.value = rtTexture2.texture;
        uniforms.u_renderpass.value = true;

        renderer.setRenderTarget(rtTexture);
        renderer.render(scene, camera, rtTexture, true);

        let buffer = rtTexture;
        rtTexture = rtTexture2;
        rtTexture2 = buffer;

        uniforms.u_buffer.value = rtTexture.texture;
        uniforms.u_resolution.value = odims;
        uniforms.u_renderpass.value = false;
      }

      function render(delta) {
        uniforms.u_mouse.value.x += (newmouse.x - uniforms.u_mouse.value.x) * divisor;
        uniforms.u_mouse.value.y += (newmouse.y - uniforms.u_mouse.value.y) * divisor;

        uniforms.u_time.value = delta * 0.0005;
        renderer.render(scene, camera);
        renderTexture();
      }

      function animate(delta) {
        animationId = requestAnimationFrame(animate);
        render(delta || 0);
      }

      // Função de limpeza para uso em React ou outros frameworks
      window.ghostMouseCleanup = function() {
        if (animationId) {
          cancelAnimationFrame(animationId);
        }
        if (renderer) {
          renderer.dispose();
        }
        window.removeEventListener('resize', onWindowResize);
        document.removeEventListener('pointermove', handlePointerMove);
        document.removeEventListener('touchmove', handlePointerMove);
      };

      })();
    }

    // Aguardar o carregamento do Three.js
    function waitForThreeJS() {
      if (window.threeJSLoadPromise) {
        window.threeJSLoadPromise.then(function() {
          initGhostMouse();
        }).catch(function(error) {
          setTimeout(function() {
            if (typeof THREE !== 'undefined') {
              initGhostMouse();
            }
          }, 2000);
        });
      } else {
        var checkCount = 0;
        var maxChecks = 50; // 5 segundos
        
        var checkInterval = setInterval(function() {
          checkCount++;
          if (typeof THREE !== 'undefined') {
            clearInterval(checkInterval);
            initGhostMouse();
          } else if (checkCount >= maxChecks) {
            clearInterval(checkInterval);
            console.error('Three.js não está disponível. Recarregue a página.');
          }
        }, 100);
      }
    }
    
    // Aguardar DOM estar pronto
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', waitForThreeJS);
    } else {
      waitForThreeJS();
    }
  </script>
</body>
</html>

View background:

Note

If this background has served you in any way, consider following me on github or supporting me to continue working at BacksEasy.