62 lines, no comments ยท 1,023 tokens, written in 13 seconds for $0.016


 1  const balls = []; const numBalls = 18; let trailGraphics;
 2  
 3  function setup() {
 4    createCanvas(600, 600);
 5    trailGraphics = createGraphics(600, 600);
 6    trailGraphics.background(15, 15, 30);
 7    colorMode(HSB, 360, 100, 100, 100);
 8    for (let i = 0; i < numBalls; i++) {
 9      balls.push({
10        x: random(40, width - 40),
11        y: random(40, height - 40),
12        vx: random(-4, 4) || 2,
13        vy: random(-4, 4) || 2,
14        r: random(12, 28),
15        hue: random(360),
16        speed: random(2, 5)
17      });
18    }
19  }
20  
21  function draw() {
22    trailGraphics.colorMode(HSB, 360, 100, 100, 100);
23    trailGraphics.noStroke();
24    trailGraphics.fill(240, 30, 12, 18);
25    trailGraphics.rect(0, 0, width, height);
26  
27    for (let b of balls) {
28      b.hue = (b.hue + 0.5) % 360;
29      let mag = sqrt(b.vx * b.vx + b.vy * b.vy);
30      b.vx = (b.vx / mag) * b.speed;
31      b.vy = (b.vy / mag) * b.speed;
32      b.x += b.vx;
33      b.y += b.vy;
34      if (b.x - b.r < 0) { b.x = b.r; b.vx *= -1; }
35      if (b.x + b.r > width) { b.x = width - b.r; b.vx *= -1; }
36      if (b.y - b.r < 0) { b.y = b.r; b.vy *= -1; }
37      if (b.y + b.r > height) { b.y = height - b.r; b.vy *= -1; }
38  
39      trailGraphics.fill(b.hue, 80, 100, 60);
40      trailGraphics.ellipse(b.x, b.y, b.r * 2);
41    }
42  
43    image(trailGraphics, 0, 0);
44  
45    for (let b of balls) {
46      noStroke();
47      let grd = drawingContext.createRadialGradient(b.x - b.r * 0.3, b.y - b.r * 0.3, b.r * 0.1, b.x, b.y, b.r);
48      grd.addColorStop(0, `hsla(${b.hue}, 100%, 95%, 1)`);
49      grd.addColorStop(0.4, `hsla(${b.hue}, 90%, 65%, 0.9)`);
50      grd.addColorStop(1, `hsla(${(b.hue + 30) % 360}, 80%, 40%, 0.2)`);
51      drawingContext.fillStyle = grd;
52      drawingContext.beginPath();
53      drawingContext.arc(b.x, b.y, b.r, 0, TWO_PI);
54      drawingContext.fill();
55  
56      noFill();
57      stroke(b.hue, 60, 100, 50);
58      strokeWeight(1.5);
59      ellipse(b.x, b.y, b.r * 2.6);
60      noStroke();
61    }
62  }