Cursor Trail

커서 트레일

A chain of dots that trails behind the cursor, each one lagging slightly — every dot chases the one in front of it.

Also known as: Mouse trailCursor particles
···
html
<div class="stage" id="stage"></div>
css
.stage{position:absolute;inset:0;cursor:none;background:
  radial-gradient(60% 60% at 30% 30%, color-mix(in srgb,var(--accent) 14%,transparent), transparent 65%)}
.tdot{position:absolute;left:0;top:0;border-radius:50%;pointer-events:none}
js
let auto=true;
addEventListener('pointerdown',()=>{auto=false;},{capture:true});
addEventListener('pointermove',()=>{auto=false;},{capture:true});
const stage=document.getElementById('stage');
const N=10;
const dots=[];
for(let i=0;i<N;i++){
  const p=i/(N-1);
  const d=document.createElement('div');
  d.className='tdot';
  const size=10-p*6;
  d.style.width=d.style.height=size+'px';
  d.style.margin=(-size/2)+'px 0 0 '+(-size/2)+'px';
  d.style.opacity=String(1-p*0.75);
  d.style.background='color-mix(in srgb, var(--accent) '+Math.round(100-p*70)+'%, var(--accent-2) '+Math.round(p*70)+'%)';
  stage.appendChild(d);
  dots.push({el:d,x:innerWidth/2,y:innerHeight/2});
}
let mx=innerWidth/2, my=innerHeight/2, t=0;
function update(){
  let px=mx, py=my;
  dots.forEach(d=>{
    d.x += (px-d.x)*0.45;
    d.y += (py-d.y)*0.45;
    d.el.style.transform='translate('+d.x+'px,'+d.y+'px)';
    px=d.x; py=d.y;
  });
}
(function loop(){
  if(auto){
    t+=0.02;
    mx=innerWidth/2+Math.sin(t)*innerWidth*0.38;
    my=innerHeight/2+Math.cos(t*1.7)*innerHeight*0.32;
  }
  update();
  requestAnimationFrame(loop);
})();
addEventListener('pointermove',e=>{ mx=e.clientX; my=e.clientY; });

Create N dots and each frame move every dot a fraction of the way toward its target: `dot[i].pos += (target - dot[i].pos) * k` (linear interpolation). The first dot's target is the real cursor; the second dot's target is the first dot's current position — chaining them this way accumulates delay down the line into a natural tail.

A smaller `k` (interpolation factor, usually 0.3–0.5) makes a longer, looser tail; a larger one hugs the cursor tightly. Shrinking size and opacity further down the chain sells the fading-away feel.

Past ~20 dots, updating DOM styles every frame gets expensive. In production you'd draw to a `<canvas>` instead, or just cap the count around 10.

When to use

Use it as decorative flair on canvas tools or experimental landing pages. In ordinary web apps it keeps drawing the eye to the cursor and becomes distracting.