friday 2/6

for scipt.js is

const canvas = document.getElementById("snakeCanvas");
const ctx = canvas.getContext("2d");

let w = window.innerWidth;
let h = window.innerHeight;
canvas.width = w;
canvas.height = h;

// Snake trail points
let points = [];
const maxPoints = 160;      // longer snake
const minDist = 4;          // spacing between points

// Mouse position
let mouseX = w / 2;
let mouseY = h / 2;

// Snake animation variables
let hue = 120;              // starting color
let hueSpeed = 0.4;         // color cycling speed
let glowStrength = 15;      // shadow blur
let breathing = 0;          // breathing animation
let autoSlither = false;    // toggle auto movement
let slitherAngle = 0;       // internal wave motion

// FPS meter
let lastTime = performance.now();
let fps = 0;

// Resize canvas
window.addEventListener("resize", () => {
  w = window.innerWidth;
  h = window.innerHeight;
  canvas.width = w;
  canvas.height = h;
});

// Mouse movement
window.addEventListener("mousemove", e => {
  updatePointer(e.clientX, e.clientY);
});

// Touch support
window.addEventListener("touchmove", e => {
  const t = e.touches[0];
  updatePointer(t.clientX, t.clientY);
});

// Click to teleport head
window.addEventListener("click", e => {
  points.push({ x: e.clientX, y: e.clientY });
});

// Update pointer and add snake points
function updatePointer(x, y) {
  const last = points[points.length - 1];

  if (!last || distance(last.x, last.y, x, y) > minDist) {
    points.push({ x, y });
    if (points.length > maxPoints) points.shift();
  }

  mouseX = x;
  mouseY = y;
}

// Distance helper
function distance(x1, y1, x2, y2) {
  const dx = x2 - x1;
  const dy = y2 - y1;
  return Math.sqrt(dx * dx + dy * dy);
}

// Draw snake
function drawSnake() {
  ctx.clearRect(0, 0, w, h);

  if (points.length < 2) return;

  ctx.lineCap = "round";
  ctx.lineJoin = "round";

  // Breathing animation
  breathing += 0.03;
  const breath = Math.sin(breathing) * 2;

  // Glow
  ctx.shadowBlur = glowStrength;
  ctx.shadowColor = "rgba(120,255,140,0.8)";

  // Draw body segments
  for (let i = 0; i < points.length - 1; i++) {
    const p1 = points[i];
    const p2 = points[i + 1];

    const t = i / points.length; // 0 → tail, 1 → head

    // Width breathing + taper
    const width = 4 + t * 12 + breath;

    // Color cycling
    const segmentHue = (hue + t * 60) % 360;

    const grad = ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);
    grad.addColorStop(0, `hsla(${segmentHue}, 80%, 45%, 0.3)`);
    grad.addColorStop(1, `hsla(${segmentHue}, 90%, 60%, 1)`);

    ctx.strokeStyle = grad;
    ctx.lineWidth = width;

    ctx.beginPath();
    ctx.moveTo(p1.x, p1.y);
    ctx.lineTo(p2.x, p2.y);
    ctx.stroke();
  }

  // Draw head
  const head = points[points.length - 1];
  ctx.beginPath();
  ctx.fillStyle = `hsla(${hue}, 100%, 70%, 1)`;
  ctx.arc(head.x, head.y, 10 + breath * 0.5, 0, Math.PI * 2);
  ctx.fill();

  // Update color cycle
  hue += hueSpeed;
}

// Auto slither movement (optional)
function autoMove() {
  if (!autoSlither) return;

  slitherAngle += 0.05;
  const radius = 80;

  const x = w / 2 + Math.cos(slitherAngle) * radius;
  const y = h / 2 + Math.sin(slitherAngle * 1.5) * radius;

  updatePointer(x, y);
}

// FPS counter
function drawFPS() {
  const now = performance.now();
  fps = 1000 / (now - lastTime);
  lastTime = now;

  ctx.fillStyle = "white";
  ctx.font = "14px monospace";
  ctx.fillText(`FPS: ${fps.toFixed(1)}`, 10, 20);
}

// Main loop
function loop() {
  autoMove();
  drawSnake();
  drawFPS();
  requestAnimationFrame(loop);
}

loop();

// Distance helper
function distance(x1, y1, x2, y2) {
  const dx = x2 - x1;
  const dy = y2 - y1;
  return Math.sqrt(dx * dx + dy * dy);
}

// Draw snake
function drawSnake() {
  ctx.clearRect(0, 0, w, h);

  if (points.length < 2) return;

  ctx.lineCap = "round";
  ctx.lineJoin = "round";

  // Breathing animation
  breathing += 0.03;
  const breath = Math.sin(breathing) * 2;

  // Glow
  ctx.shadowBlur = glowStrength;
  ctx.shadowColor = "rgba(120,255,140,0.8)";

  // Draw body segments
  for (let i = 0; i < points.length - 1; i++) {
    const p1 = points[i];
    const p2 = points[i + 1];

    const t = i / points.length; // 0 → tail, 1 → head

    // Width breathing + taper
    const width = 4 + t * 12 + breath;

    // Color cycling
    const segmentHue = (hue + t * 60) % 360;

    const grad = ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y);
    grad.addColorStop(0, `hsla(${segmentHue}, 80%, 45%, 0.3)`);
    grad.addColorStop(1, `hsla(${segmentHue}, 90%, 60%, 1)`);

    ctx.strokeStyle = grad;
    ctx.lineWidth = width;

    ctx.beginPath();
    ctx.moveTo(p1.x, p1.y);
    ctx.lineTo(p2.x, p2.y);
    ctx.stroke();
  }

  // Draw head
  const head = points[points.length - 1];
  ctx.beginPath();
  ctx.fillStyle = `hsla(${hue}, 100%, 70%, 1)`;
  ctx.arc(head.x, head.y, 10 + breath * 0.5, 0, Math.PI * 2);
  ctx.fill();

  // Update color cycle
  hue += hueSpeed;
}

// Auto slither movement (optional)
function autoMove() {
  if (!autoSlither) return;

  slitherAngle += 0.05;
  const radius = 80;

  const x = w / 2 + Math.cos(slitherAngle) * radius;
  const y = h / 2 + Math.sin(slitherAngle * 1.5) * radius;

  updatePointer(x, y);
}

// FPS counter
function drawFPS() {
  const now = performance.now();
  fps = 1000 / (now - lastTime);
  lastTime = now;

  ctx.fillStyle = "white";
  ctx.font = "14px monospace";
  ctx.fillText(`FPS: ${fps.toFixed(1)}`, 10, 20);
}

// Main loop
function loop() {
  autoMove();
  drawSnake();
  drawFPS();
  requestAnimationFrame(loop);
}

loop();

i used ai cause there wasn’t much videos i could find with it and for the index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Point to Point Snake</title>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <canvas id="snakeCanvas"></canvas>
  <script src="script.js"></script>
</body>
</html>

and for the style.cs

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background: #111;
  overflow: hidden;
  cursor: none;
}

#snakeCanvas {
  display: block;
}

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top