<== Back

Resources

Made by me

Feel free to use those in any way you want. Credit is not mandatory, but appreciated!

  • Customizable, character-based cursor trail
/* Usage : add a <script></script> tag in your page after the body, and either put this code in the tag 
 * or put it in a .js file and link it like <script src="/your/script/path.js"></script>
*/

/* Parameters to customize to your liking */

// The amount of time each particle stays on the screen
const maxLife = 120;
// The starting size of the particle
const maxSize = 1.3;
// The minimum amount of pixel difference before spawning a new particle
const minInterval = 20;

// Horizontal offset where the particles start, relative to the cursor point
const xOffset = 10;
// Vertical offset where the particles start, relative to the cursor point
const yOffset = 32;

// The moment when the particle starts fading out. The fade out is a simple size reduction until it reaches 0
const fadeOutStart = 80;
// The amount of size reduced at each reduction step
const fadeOutSpeed = 0.04;

// The list of all colors the particles can be (random)
const possibleColors = ["#6367FF","#8494FF","#C9BEFF","#FFDBFD"];
// The list of all characters the particles can be (random)
const possibleCharacters = "*☆✯✻✧";


/* Functions */

var particles = [];
var width = window.innerWidth;
var height = window.innerHeight;
var canvas, context
var lastPos = { x: width / 2, y: width / 2 };

const prefersReducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)"
);

function onWindowResize(e) {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
}

function OnMouseMove(e) {
    finalX = e.clientX + xOffset;
    finalY = e.clientY + yOffset;

    const interval = Math.hypot(
        finalX - lastPos.x,
        finalY - lastPos.y
    );
    if (interval > minInterval)
    {
        SpawnParticle(finalX, finalY);
        lastPos.x = finalX;
        lastPos.y = finalY;
    }
}

function SpawnParticle(x, y) {
    var color = possibleColors[Math.floor(Math.random() * possibleColors.length)];
    particles.push({
        x: x, 
        y: y,
        size: maxSize,
        lifetime: 0, 
        color: color, 
        direction: 0.5 - Math.random() * 0.7,
        character: possibleCharacters[Math.floor(Math.random() * possibleCharacters.length)]
    });
}

function UpdateParticles() {
    if (particles.length == 0) {
      return;
    }

    context.clearRect(0, 0, width, height);

    particles = particles.filter((particle) => particle.lifetime < maxLife);
    particles.forEach((particle) => {
        particle.lifetime++;
        particle.y++;
        particle.x += particle.direction;
        if(particle.lifetime >= fadeOutStart && particle.size - fadeOutSpeed >= 0.0)
        {
            particle.size -= fadeOutSpeed;
        }
        context.fillStyle = particle.color;
        context.font = `${particle.size}em sans-serif`;
        context.fillText(particle.character, particle.x, particle.y);
    });
}

function loop() {
    UpdateParticles();
    animationFrame = requestAnimationFrame(loop);
}

function init() {
    canvas = document.createElement("canvas");
    context = canvas.getContext("2d");
    canvas.style.position = "fixed";
    canvas.style.top = "0px";
    canvas.style.left = "0px";
    canvas.width = width;
    canvas.height = height;
    canvas.style.pointerEvents = "none"; 
    canvas.style.zIndex = "10";

    document.body.appendChild(canvas);
    window.addEventListener("mousemove", OnMouseMove);
    window.addEventListener("resize", onWindowResize);
    loop();
}

init();
						

Made by others

The Windows XP pipes screensaver SorenOS sitting on your browser