I took my son to his first drum lesson. The teacher put a PDF on a big white screen, and I could barely follow the cursor. Same thing happens on work calls when I'm sharing my screen: I want people to look there, and the default pointer doesn't cut it.
I didn't want another menu-bar app or a Chrome extension chewing RAM 24/7. A bookmarklet is enough: click once and a circle follows the mouse; click again and it goes away.
Features
- Toggle with one click — On/off from the same bookmark.
- Contrast-aware color — The ring picks a color that tends to read against whatever is behind the cursor (cyan vs magenta style).
- Optional motion tail — Press Ctrl+6+7+8 (in order, with Ctrl held) for a more obvious trail; same combo turns it off.
- Zero install footprint — It's a bookmark, not a background service.
How to use it
- Install the bookmark (drag the button at the top or bottom of this page to your bookmarks bar, or paste the code below into a bookmark URL).
- On any normal web page, click the bookmark to turn the highlight on.
- Click again to remove it.
- If you need the tail, use the Ctrl+6+7+8 chord once to enable and once to disable.
Install (alternate)
If drag-and-drop is awkward: copy everything inside the code block below, create a new bookmark, paste into the URL field, and save.
Bookmarklet Code:
javascript:(function(){if(window.cursorHighlighter){window.cursorHighlighter.remove();window.cursorHighlighter=null;window.cursorHighlighterCanvas?.remove();window.cursorHighlighterCanvas=null;cancelAnimationFrame(window.cursorHighlighterAnim);document.removeEventListener('mousemove',window.cursorHighlighterMove);document.removeEventListener('click',window.cursorHighlighterClick);document.removeEventListener('keydown',window.cursorHighlighterKey);window.cursorHighlighterKeySeq=null;window.cursorHighlighterParticles=null;return;}const ball=document.createElement('div');ball.id='cursor-highlighter';ball.style.cssText='position:fixed;width:36px;height:36px;border-radius:50%;pointer-events:none;z-index:2147483647;transition:transform 0.15s ease,box-shadow 0.15s ease;mix-blend-mode:difference;border:2px solid;';document.body.appendChild(ball);const canvas=document.createElement('canvas');canvas.style.cssText='position:fixed;top:0;left:0;width:100vw;height:100vh;pointer-events:none;z-index:2147483646;display:none;';canvas.width=window.innerWidth;canvas.height=window.innerHeight;document.body.appendChild(canvas);const ctx=canvas.getContext('2d');let currentColor='#00FFFF';let tailEnabled=false;let cursor={x:0,y:0};let particles=[];const particleCount=25;const trailSpeed=0.4;function getContrastColor(x,y){const el=document.elementFromPoint(x,y);if(!el)return'#00FFFF';const bg=window.getComputedStyle(el).backgroundColor;const match=bg.match(/\d+/g);if(!match||match.length<3)return'#00FFFF';const r=parseInt(match[0]),g=parseInt(match[1]),b=parseInt(match[2]);const luminance=0.299*r+0.587*g+0.114*b;return luminance>128?'#FF00FF':'#00FFFF';}function hexToRgb(hex){const r=parseInt(hex.slice(1,3),16);const g=parseInt(hex.slice(3,5),16);const b=parseInt(hex.slice(5,7),16);return{r,g,b};}function updateParticles(){if(!tailEnabled)return;ctx.clearRect(0,0,canvas.width,canvas.height);let x=cursor.x;let y=cursor.y;particles.forEach((particle,index)=>{const nextParticle=particles[index+1]||particles[0];particle.x=x;particle.y=y;x+=(nextParticle.x-particle.x)*trailSpeed;y+=(nextParticle.y-particle.y)*trailSpeed;});ctx.lineCap='round';ctx.lineJoin='round';const rgb=hexToRgb(currentColor);for(let i=1;i<particles.length;i++){const progress=i/particles.length;const alpha=1-progress;const width=15*(1-progress);ctx.strokeStyle=`rgba(${rgb.r},${rgb.g},${rgb.b},${alpha})`;ctx.lineWidth=width;ctx.beginPath();ctx.moveTo(particles[i-1].x,particles[i-1].y);ctx.lineTo(particles[i].x,particles[i].y);ctx.stroke();}}function animLoop(){updateParticles();window.cursorHighlighterAnim=requestAnimationFrame(animLoop);}window.cursorHighlighterMove=function(e){const color=getContrastColor(e.clientX,e.clientY);ball.style.left=(e.clientX-18)+'px';ball.style.top=(e.clientY-18)+'px';ball.style.backgroundColor=color;ball.style.borderColor=color;ball.style.boxShadow='none';currentColor=color;cursor.x=e.clientX;cursor.y=e.clientY;if(tailEnabled&&particles.length===0){for(let i=0;i<particleCount;i++){particles.push({x:cursor.x,y:cursor.y});}}};window.cursorHighlighterClick=function(e){ball.style.transform='scale(0.7)';ball.style.boxShadow=`0 0 20px ${currentColor}, 0 0 40px ${currentColor}, 0 0 60px ${currentColor}`;setTimeout(()=>{ball.style.transform='scale(1)';ball.style.boxShadow='none';},150);};let keySeq='';let keyTimer;window.cursorHighlighterKey=function(e){if(e.ctrlKey){keySeq+=e.key;clearTimeout(keyTimer);keyTimer=setTimeout(()=>keySeq='',1000);if(keySeq.includes('678')){tailEnabled=!tailEnabled;canvas.style.display=tailEnabled?'block':'none';if(tailEnabled){particles=[];for(let i=0;i<particleCount;i++){particles.push({x:cursor.x,y:cursor.y});}}else{particles=[];ctx.clearRect(0,0,canvas.width,canvas.height);}keySeq='';}}};window.addEventListener('resize',()=>{canvas.width=window.innerWidth;canvas.height=window.innerHeight;});document.addEventListener('mousemove',window.cursorHighlighterMove);document.addEventListener('click',window.cursorHighlighterClick);document.addEventListener('keydown',window.cursorHighlighterKey);animLoop();window.cursorHighlighter=ball;window.cursorHighlighterCanvas=canvas;window.cursorHighlighterParticles=particles;})();