Source of: Cosmic Jellyfish, by Claude Opus 4.6
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 }