let isMobile = /iPhone|iPod|Android/i.test(navigator.userAgent); let repel_radius, radius_, angle = 0; let points = []; // Cranked up counts const particles = isMobile ? 6000 : 20000; const attraction = 0.02; // Snappier return for faster spin const damping = 0.82; const repel_strength = 45; const spinSpeed = 0.04; // Significantly faster rotation function setup() { createCanvas(windowWidth, windowHeight); radius_ = min(width, height) * (isMobile ? 0.35 : 0.4); repel_radius = isMobile ? 80 : 150; pixelDensity(1); colorMode(HSB, 360, 100, 100, 100); for (let i = 0; i < particles; i++) { // We use pre-calculated indices to create the shell structure points.push({ id: i, pos: createVector(random(-width, width), random(-height, height)), vel: createVector(0, 0), // Unique math offsets for the spherical "weave" phi: acos(random(-1, 1)), theta: random(TWO_PI) }); } background(0); } function draw() { // Persistent trails create the "silk" texture at high speeds background(0, 0, 0, 15); translate(width / 2, height / 2); let mouse = createVector(mouseX - width / 2, mouseY - height / 2); for (let i = 0; i < points.length; i++) { let p = points[i]; // Faster 3D rotation math // We calculate the "Home" position on a rotating sphere let xMod = sin(angle + p.id * 0.001); let zMod = cos(angle + p.id * 0.001); let homeX = xMod * sin(p.id) * radius_; let homeY = cos(p.id) * radius_; let homeZ = zMod * sin(p.id) * radius_; // Physics: Spring to Home let dx = homeX - p.pos.x; let dy = homeY - p.pos.y; p.vel.x += dx * attraction; p.vel.y += dy * attraction; // Interaction: Repulsion let amx = p.pos.x - mouse.x; let amy = p.pos.y - mouse.y; let d2 = amx * amx + amy * amy; if (d2 < repel_radius * repel_radius) { let d = sqrt(d2); let force = (1 - d / repel_radius) * repel_strength; p.vel.x += (amx / d) * force; p.vel.y += (amy / d) * force; } // Apply velocities p.vel.x *= damping; p.vel.y *= damping; p.pos.x += p.vel.x; p.pos.y += p.vel.y; // Depth-based visuals // Points in front are brighter and thicker let alpha = map(homeZ, -radius_, radius_, 10, 80); let weight = map(homeZ, -radius_, radius_, 0.5, 3); stroke(200, 5, 100, alpha); strokeWeight(weight); point(p.pos.x, p.pos.y); } angle += spinSpeed; } function windowResized() { resizeCanvas(windowWidth, windowHeight); radius_ = min(width, height) * 0.4; background(0); }