Pendulum Painting

by Ben Gillbanks

HTML

<input type="color" id="colorPicker" value="#000000">
<canvas id="canvas"></canvas>

CSS

body { display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; }
  canvas { border: 1px solid #ccc; }
  input {
      position: absolute;
      top:0;
      left: 0;
      z-index:10;
  }

JavaScript

document.addEventListener('DOMContentLoaded', () => {
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    if (!canvas || !ctx) {
        console.error('Canvas or context not supported.');
        return;
    }

    const velocityScale = 0.3;
    const velocityThreshold = 0.5;
    const maxLineWidth = 15;
    const damping = 0.9997;
    const gravity = 0.1;
    const SPLATTER_CHANCE = 0.95;
    const DRIP_CHANCE = 0.9;
    const MOVEMENT_TIMEOUT = 10;

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

    ctx.fillStyle = '#FFFFFF';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    const centerX = canvas.width / 2;
    const centerY = canvas.height / 2;
    let painting = false;
    let startX = 0, startY = 0, velocityX = 0, velocityY = 0, lastX = 0, lastY = 0;

    canvas.addEventListener('mousedown', e => {
        startX = e.clientX;
        startY = e.clientY;
        lastX = startX;
        lastY = startY;
        painting = true;
        velocityX = 0;
        velocityY = 0;
    });

    let moveTimer;
    canvas.addEventListener('mousemove', e => {
        clearTimeout(moveTimer);
        moveTimer = setTimeout(() => {
            if (painting) {
                velocityX = (e.clientX - lastX) * velocityScale;
                velocityY = (e.clientY - lastY) * velocityScale;
                lastX = e.clientX;
                lastY = e.clientY;
            }
        }, MOVEMENT_TIMEOUT);
    });

    canvas.addEventListener('mouseup', () => {
        painting = false;
        simulatePendulumMovement(lastX, lastY, velocityX, velocityY, document.getElementById('colorPicker').value);
    });

    function simulatePendulumMovement(x, y, vx, vy, color) {
        function draw() {
            requestAnimationFrame(draw);
            if (Math.sqrt(vx * vx + vy * vy) > velocityThreshold) {
                vx *= damping;
                vy *= damping;

                if (Math.random()...