Interactive Snake Animation with Glowing Effects that Follows Your Cursor (Free Source Code)

This project demonstrates how to create an interactive snake animation using HTML5 Canvas and JavaScript. The snake dynamically follows the mouse cursor, leaving a glowing green trail. Additionally, the animation features starry background effects and moving "legs" to add visual interest.

Key Features:

  • Dynamic Interaction: The snake's head tracks the mouse movements smoothly.
  • Glowing Trail: The segments of the snake emit a vibrant green glow.
  • Realistic Motion: The snake's body segments and legs move naturally, maintaining a cohesive flow.
  • Starry Background: A randomly generated night sky with twinkling stars enhances the visual appeal.

This code is perfect for creative developers looking to enhance their web pages with engaging animations or for learning canvas manipulation techniques.

Below is the full code snippet:


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Snake Skeleton</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background-color: #000;
        }

        canvas {
            display: block;
        }
    </style>
</head>
<body>

<canvas id="snakeCanvas"></canvas>

<script>
    const canvas = document.getElementById('snakeCanvas');
    const ctx = canvas.getContext('2d');
    const segmentCount = 50; 
    const spacing = 20;

    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    let mousePos = { x: 0, y: 0 };

    const segments = [];
    const legs = [];
    const stars = [];

    for (let i = 0; i < segmentCount; i++) {
        segments.push({
            x: canvas.width / 2,
            y: canvas.height / 2,
            angle: 0
        });
    }

    for (let i = 0; i < segmentCount * 2; i++) {
        legs.push({
            angle: Math.random() * Math.PI * 2,
            speed: 0.1 + Math.random() * 0.1
        });
    }

    for (let i = 0; i < 100; i++) {
        stars.push({
            x: Math.random() * canvas.width,
            y: Math.random() * canvas.height,
            radius: Math.random() * 2 + 1,
            opacity: Math.random()
        });
    }

    canvas.addEventListener('mousemove', (e) => {
        const rect = canvas.getBoundingClientRect();
        mousePos = {
            x: e.clientX - rect.left,
            y: e.clientY - rect.top
        };
    });

    function animate() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        stars.forEach(star => {
            ctx.beginPath();
            ctx.arc(star.x, star.y, star.radius, 0, Math.PI * 2);
            ctx.fillStyle = `rgba(255, 255, 255, ${star.opacity})`;
            ctx.fill();
            star.opacity += (Math.random() - 0.5) * 0.05; 
            if (star.opacity < 0) star.opacity = 0;
            if (star.opacity > 1) star.opacity = 1;
        });

        ctx.lineWidth = 4;
        ctx.strokeStyle = 'rgba(0, 255, 0, 0.7)'; 
        ctx.shadowColor = 'rgba(0, 255, 0, 0.7)'; 
        ctx.shadowBlur = 20; 

        for (let i = 0; i < segments.length; i++) {
            const segment = segments[i];

            if (i === 0) {
                const dx = mousePos.x - segment.x;
                const dy = mousePos.y - segment.y;
                const targetAngle = Math.atan2(dy, dx);
                segment.angle = targetAngle;
                segment.x += Math.cos(segment.angle) * 10; 
                segment.y += Math.sin(segment.angle) * 10;
            } else {
                const prevSegment = segments[i - 1];
                const dx = prevSegment.x - segment.x;
                const dy = prevSegment.y - segment.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                if (distance > spacing) {
                    segment.x += (dx / distance) * (distance - spacing);
                    segment.y += (dy / distance) * (distance - spacing);
                }
                segment.angle = Math.atan2(dy, dx);
            }
        }

        ctx.beginPath();
        ctx.moveTo(segments[0].x, segments[0].y);
        segments.forEach((segment, i) => {
            if (i > 0) {
                ctx.lineTo(segment.x, segment.y);
            }
        });
        ctx.stroke();

        segments.forEach((segment, i) => {
            const leftLeg = legs[i * 2];
            const rightLeg = legs[i * 2 + 1];

            leftLeg.angle += leftLeg.speed;
            rightLeg.angle += rightLeg.speed;

            ctx.beginPath();
            ctx.moveTo(segment.x, segment.y);
            const leftX = segment.x + Math.cos(segment.angle - Math.PI / 2) * 25;
            const leftY = segment.y + Math.sin(segment.angle - Math.PI / 2) * 25;
            ctx.lineTo(leftX + Math.cos(leftLeg.angle) * 15, leftY + Math.sin(leftLeg.angle) * 15);
            ctx.stroke();

            ctx.beginPath();
            ctx.moveTo(segment.x, segment.y);
            const rightX = segment.x + Math.cos(segment.angle + Math.PI / 2) * 25;
            const rightY = segment.y + Math.sin(segment.angle + Math.PI / 2) * 25;
            ctx.lineTo(rightX + Math.cos(rightLeg.angle) * 15, rightY + Math.sin(rightLeg.angle) * 15);
            ctx.stroke();
        });

        requestAnimationFrame(animate);
    }

    animate();
</script>

</body>
</html>
  

Post a Comment

Previous Post Next Post