173 lines, 5 of them comments ยท 2,138 tokens, written in 28 seconds for $0.055


  1  let jellyfish = [];
  2  let particles = [];
  3  
  4  function setup() {
  5    createCanvas(windowWidth, windowHeight);
  6    colorMode(HSB, 360, 100, 100, 100);
  7    for (let i = 0; i < 3; i++) {
  8      jellyfish.push(new Jellyfish(random(width), random(height)));
  9    }
 10    for (let i = 0; i < 150; i++) {
 11      particles.push(new Particle());
 12    }
 13  }
 14  
 15  function draw() {
 16    background(240, 80, 8, 25);
 17    for (let p of particles) {
 18      p.update();
 19      p.display();
 20    }
 21    for (let j of jellyfish) {
 22      j.update();
 23      j.display();
 24    }
 25  }
 26  
 27  class Jellyfish {
 28    constructor(x, y) {
 29      this.x = x;
 30      this.y = y;
 31      this.baseHue = random(160, 300);
 32      this.size = random(60, 120);
 33      this.phase = random(TWO_PI);
 34      this.speed = random(0.3, 0.8);
 35      this.tentacles = [];
 36      let numTentacles = floor(random(6, 12));
 37      for (let i = 0; i < numTentacles; i++) {
 38        this.tentacles.push({
 39          offsetX: map(i, 0, numTentacles - 1, -this.size * 0.4, this.size * 0.4),
 40          length: random(80, 180),
 41          phase: random(TWO_PI),
 42          freq: random(0.02, 0.05),
 43          amp: random(10, 30)
 44        });
 45      }
 46      this.vx = 0;
 47      this.vy = 0;
 48    }
 49  
 50    update() {
 51      this.phase += 0.03;
 52      let pulse = sin(this.phase);
 53      this.vy += -0.02 - pulse * 0.03;
 54      let dx = mouseX - this.x;
 55      let dy = mouseY - this.y;
 56      let dist2 = dx * dx + dy * dy;
 57      if (dist2 < 40000) {
 58        let d = sqrt(dist2) + 1;
 59        this.vx -= (dx / d) * 0.5;
 60        this.vy -= (dy / d) * 0.5;
 61      }
 62      this.vx += random(-0.05, 0.05);
 63      this.vy += random(-0.02, 0.02);
 64      this.vx *= 0.98;
 65      this.vy *= 0.98;
 66      this.x += this.vx;
 67      this.y += this.vy;
 68      if (this.x < -this.size) this.x = width + this.size;
 69      if (this.x > width + this.size) this.x = -this.size;
 70      if (this.y < -this.size * 2) this.y = height + this.size;
 71      if (this.y > height + this.size) this.y = -this.size * 2;
 72    }
 73  
 74    display() {
 75      push();
 76      translate(this.x, this.y);
 77      let pulse = sin(this.phase);
 78      let sw = this.size * (1 + pulse * 0.15);
 79      let sh = this.size * 0.6 * (1 - pulse * 0.2);
 80  
 81      // Glow
 82      noStroke();
 83      for (let g = 5; g > 0; g--) {
 84        fill(this.baseHue, 60, 80, 3);
 85        ellipse(0, 0, sw + g * 20, sh + g * 20);
 86      }
 87  
 88      // Bell
 89      for (let i = 5; i > 0; i--) {
 90        let t = i / 5;
 91        fill(this.baseHue + t * 20, 50 + t * 30, 60 + t * 30, 15 + t * 20);
 92        ellipse(0, 0, sw * t, sh * t);
 93      }
 94  
 95      // Inner pattern
 96      fill((this.baseHue + 30) % 360, 80, 90, 30);
 97      ellipse(0, sh * 0.1, sw * 0.3, sh * 0.3);
 98  
 99      // Tentacles
100      noFill();
101      for (let t of this.tentacles) {
102        strokeWeight(1.5);
103        stroke(this.baseHue + 20, 60, 80, 40);
104        beginShape();
105        let startX = t.offsetX;
106        let startY = sh * 0.3;
107        for (let j = 0; j <= 30; j++) {
108          let frac = j / 30;
109          let tx = startX + sin(t.phase + frameCount * t.freq + frac * 5) * t.amp * frac;
110          let ty = startY + frac * t.length + sin(this.phase + frac * 3) * 5;
111          vertex(tx, ty);
112        }
113        endShape();
114      }
115  
116      // Small glowing dots on tentacle tips
117      noStroke();
118      for (let t of this.tentacles) {
119        let frac = 1;
120        let tx = t.offsetX + sin(t.phase + frameCount * t.freq + frac * 5) * t.amp * frac;
121        let ty = sh * 0.3 + t.length + sin(this.phase + 3) * 5;
122        fill((this.baseHue + 60) % 360, 50, 100, 50 + sin(frameCount * 0.1 + t.phase) * 30);
123        ellipse(tx, ty, 4, 4);
124      }
125  
126      pop();
127    }
128  }
129  
130  class Particle {
131    constructor() {
132      this.reset();
133      this.y = random(height);
134    }
135  
136    reset() {
137      this.x = random(width);
138      this.y = random(height);
139      this.size = random(1, 4);
140      this.hue = random(160, 300);
141      this.brightness = random(50, 100);
142      this.alpha = random(10, 50);
143      this.vx = random(-0.2, 0.2);
144      this.vy = random(-0.5, -0.1);
145      this.flickerSpeed = random(0.02, 0.08);
146      this.flickerPhase = random(TWO_PI);
147    }
148  
149    update() {
150      this.x += this.vx + sin(frameCount * 0.01 + this.flickerPhase) * 0.1;
151      this.y += this.vy;
152      if (this.y < -10) {
153        this.reset();
154        this.y = height + 10;
155      }
156      if (this.x < -10) this.x = width + 10;
157      if (this.x > width + 10) this.x = -10;
158    }
159  
160    display() {
161      let flicker = sin(frameCount * this.flickerSpeed + this.flickerPhase);
162      let a = this.alpha + flicker * 20;
163      noStroke();
164      fill(this.hue, 50, this.brightness, a * 0.3);
165      ellipse(this.x, this.y, this.size * 4);
166      fill(this.hue, 60, this.brightness, a);
167      ellipse(this.x, this.y, this.size);
168    }
169  }
170  
171  function windowResized() {
172    resizeCanvas(windowWidth, windowHeight);
173  }