Source of: Cosmic Jellyfish, by Claude Opus 4.6
146 lines, 5 of them comments ยท 1,850 tokens, written in 25 seconds for $0.048
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 < 6; i++) {
8 jellyfish.push(new Jellyfish(random(width), random(height)));
9 }
10 }
11
12 function draw() {
13 background(240, 60, 8, 25);
14
15 // stars
16 randomSeed(42);
17 for (let i = 0; i < 150; i++) {
18 let sx = random(width);
19 let sy = random(height);
20 let sb = 40 + 60 * sin(frameCount * 0.02 + i);
21 noStroke();
22 fill(60, 10, sb, 50);
23 circle(sx, sy, random(1, 3));
24 }
25
26 for (let j of jellyfish) {
27 j.update();
28 j.display();
29 }
30
31 for (let i = particles.length - 1; i >= 0; i--) {
32 particles[i].update();
33 particles[i].display();
34 if (particles[i].life <= 0) particles.splice(i, 1);
35 }
36 }
37
38 class Jellyfish {
39 constructor(x, y) {
40 this.x = x;
41 this.y = y;
42 this.baseHue = random(160, 320);
43 this.size = random(40, 80);
44 this.speed = random(0.3, 0.8);
45 this.wobble = random(1000);
46 this.tentacles = [];
47 this.numTentacles = floor(random(5, 9));
48 for (let i = 0; i < this.numTentacles; i++) {
49 this.tentacles.push([]);
50 }
51 this.phase = random(TWO_PI);
52 }
53
54 update() {
55 let mx = (mouseX - this.x) * 0.003;
56 let my = (mouseY - this.y) * 0.003;
57 this.wobble += 0.01;
58 this.x += sin(this.wobble * 1.3) * 0.8 + mx;
59 this.y -= this.speed + sin(this.wobble) * 0.3 - my * 0.5;
60 this.phase += 0.05;
61
62 if (this.y < -this.size * 3) this.y = height + this.size * 2;
63 if (this.x < -this.size * 2) this.x = width + this.size * 2;
64 if (this.x > width + this.size * 2) this.x = -this.size * 2;
65
66 for (let i = 0; i < this.numTentacles; i++) {
67 let tx = this.x + map(i, 0, this.numTentacles - 1, -this.size * 0.6, this.size * 0.6);
68 let ty = this.y + this.size * 0.3;
69 this.tentacles[i].unshift({x: tx, y: ty});
70 if (this.tentacles[i].length > 30) this.tentacles[i].pop();
71 }
72
73 if (random() < 0.1) {
74 particles.push(new Particle(this.x + random(-this.size/2, this.size/2), this.y, this.baseHue));
75 }
76 }
77
78 display() {
79 push();
80 let pulse = sin(this.phase) * 0.15 + 1;
81 let sw = this.size * pulse;
82 let sh = this.size * 0.7 * (1 / pulse);
83
84 // glow
85 for (let g = 3; g > 0; g--) {
86 noStroke();
87 fill(this.baseHue, 70, 80, 5);
88 ellipse(this.x, this.y, sw * (1 + g * 0.4), sh * (1 + g * 0.4));
89 }
90
91 // body
92 noStroke();
93 for (let i = 10; i > 0; i--) {
94 let inter = i / 10;
95 fill(this.baseHue, 50 + inter * 30, 60 + inter * 30, 40 + inter * 30);
96 ellipse(this.x, this.y, sw * inter, sh * inter);
97 }
98
99 // dome highlight
100 fill(this.baseHue, 20, 100, 20);
101 ellipse(this.x - sw * 0.15, this.y - sh * 0.15, sw * 0.3, sh * 0.25);
102
103 // tentacles
104 for (let i = 0; i < this.numTentacles; i++) {
105 let t = this.tentacles[i];
106 noFill();
107 for (let w = 3; w > 0; w--) {
108 stroke(this.baseHue, 60, 70, 10 + w * 5);
109 strokeWeight(w * 1.5);
110 beginShape();
111 for (let j = 0; j < t.length; j++) {
112 let wavex = sin(j * 0.3 + this.wobble * 2 + i) * (j * 0.5);
113 curveVertex(t[j].x + wavex, t[j].y + j * 2);
114 }
115 endShape();
116 }
117 }
118 pop();
119 }
120 }
121
122 class Particle {
123 constructor(x, y, hue) {
124 this.x = x;
125 this.y = y;
126 this.hue = hue + random(-20, 20);
127 this.life = 100;
128 this.vx = random(-0.5, 0.5);
129 this.vy = random(-1, 0.5);
130 this.size = random(2, 5);
131 }
132 update() {
133 this.x += this.vx;
134 this.y += this.vy;
135 this.life -= 1.2;
136 }
137 display() {
138 noStroke();
139 fill(this.hue % 360, 60, 80, this.life * 0.5);
140 circle(this.x, this.y, this.size * (this.life / 100));
141 }
142 }
143
144 function windowResized() {
145 resizeCanvas(windowWidth, windowHeight);
146 }