Source of: Repulsive Orbs, by o3
67 lines, 6 of them comments ยท 1,057 tokens, written in 7 seconds for $0.0087
1 let particles = [];
2 const NUM = 600;
3
4 function setup() {
5 createCanvas(windowWidth, windowHeight);
6 colorMode(HSB, 360, 100, 100, 100);
7 noStroke();
8 for (let i = 0; i < NUM; i++) {
9 particles.push(new Orb());
10 }
11 background(0);
12 }
13
14 function draw() {
15 // Translucent background for motion blur
16 fill(0, 0, 0, 10);
17 rect(0, 0, width, height);
18 translate(width / 2, height / 2);
19 for (let p of particles) {
20 p.update();
21 p.show();
22 }
23 }
24
25 class Orb {
26 constructor() {
27 this.angle = random(TWO_PI);
28 this.baseR = random(50, min(width, height) * 0.45);
29 this.r = this.baseR;
30 this.speed = random(0.002, 0.01) * (random() < 0.5 ? 1 : -1);
31 this.hue = map(this.baseR, 50, min(width, height) * 0.45, 180, 360);
32 }
33
34 update() {
35 // Natural orbit
36 this.angle += this.speed;
37
38 // Mouse interaction (repulsion)
39 let mx = mouseX - width / 2;
40 let my = mouseY - height / 2;
41 let px = cos(this.angle) * this.r;
42 let py = sin(this.angle) * this.r;
43 let d = dist(mx, my, px, py);
44 if (d < 120) {
45 // Push outward proportionally
46 this.r += (120 - d) * 0.3;
47 }
48
49 // Ease radius back toward base radius
50 this.r = lerp(this.r, this.baseR, 0.02);
51 }
52
53 show() {
54 let x = cos(this.angle) * this.r;
55 let y = sin(this.angle) * this.r;
56 fill((this.hue + frameCount * 0.3) % 360, 80, 100, 80);
57 ellipse(x, y, 4, 4);
58 }
59 }
60
61 function windowResized() {
62 resizeCanvas(windowWidth, windowHeight);
63 // Recalculate base radius range for particles
64 for (let p of particles) {
65 p.baseR = constrain(p.baseR, 50, min(width, height) * 0.45);
66 }
67 }