Qué estás viendo
El anillo azul del cursor y el primer cuadrado usan el mismo número: dónde está el mouse en la ventana. Los otros dos cuadrados no saltan ahí: cada fotograma se acercan un poco al de adelante. Por eso hay cola.
Baja el slider: la cola se alarga. Súbelo: se juntan. Eso no es “más distancia de más”, es menos fracción por frame.
1 · El lerp
Lerp = interpolación lineal. En vez de poner la posición igual al destino, avanzas solo una parte del camino, 60 veces por segundo:
posicion += (destino - posicion) * ease;
ease entre 0 y 1. Cerca de 1: llega ya. Cerca de 0: perezoso.
El número del slider es ese ease (en el código aparece aquí:
0.25).
El bucle es requestAnimationFrame: el navegador llama a tu
función antes de pintar cada frame. Sin eso, el lerp no se mueve solo.
2 · Dos mapas distintos (aquí estaba el bug)
El mouse te da e.clientX y e.clientY: píxeles
desde la esquina de la ventana. El anillo del cursor se mueve con
eso, en position: fixed.
Un recuadro del medio de la página es otro mapa: su esquina no es (0, 0) de la ventana. Si haces esto:
x = e.clientX - recuadro.left; el.style.left = x + 'px';
left se mide desde el bloque padre. Si ese padre es un
flex centrado, el (0, 0) de los cuadrados no es la esquina del
recuadro: es el centro, junto al texto. Estás sumando “posición del
mouse” encima de “ya estaba en el centro”. Resultado: el anillo arriba
a la izquierda y el naranja abajo a la derecha. Parece lerp lento. No lo
es. Son sistemas de coordenadas distintos.
Subir el ease no lo arregla. “Nacer en el cursor” tampoco, si el origen sigue mal.
3 · La receta que sí pega
Usa el mapa de la ventana, el mismo del anillo:
- Guarda
clientX/clientY. El recuadro solo sirve para saber si el mouse está dentro (mostrar u ocultar). - Saca los bloques del recuadro (
document.body.appendChild). Si se quedan dentro,transformuoverflowdel padre convierten unposition: fixeden coordenadas del recuadro otra vez. Mismo síntoma: siguen de lejos. - Pon
position: fixed; top: 0; left: 0después de moverlos albody, no en el CSS mientras siguen dentro. - Muévelos igual que el cursor:
translate(xpx, ypx) translate(-50%, -50%).
let mx = 0, my = 0, dentro = false;
window.addEventListener('mousemove', e => {
mx = e.clientX;
my = e.clientY;
const r = zona.getBoundingClientRect();
dentro = mx >= r.left && mx <= r.right && my >= r.top && my <= r.bottom;
});
function animar(){
primero.x = mx; // pegado al mouse
primero.y = my;
cola.x += (primero.x - cola.x) * ease; // lerp
cola.y += (primero.y - cola.y) * ease;
el.style.transform = `translate(${x}px, ${y}px) translate(-50%,-50%)`;
requestAnimationFrame(animar);
}
4 · La cola
No hace falta que los tres persigan al mouse. El 0 copia el mouse; el 1 persigue al 0; el 2 persigue al 1, un poco más lento:
bloques[0] → mouse (sin lerp) bloques[1] → bloques[0] (ease) bloques[2] → bloques[1] (ease * 0.7)
Así el retraso es real y se ve. El desfase a medio recuadro no era eso.
Por qué importa
El anillo del cursor, la cabeza del búho y estos bloques son la misma línea. Si el lerp “no pega”, primero pregunta: ¿estoy en el mismo mapa que el mouse? Luego ajusta el ease.