Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Ultimate p5.js Particle System</title> | |
<style> | |
body { margin: 0; display: flex; justify-content: center; align-items: center; min-height: 100vh; background: #111; } | |
canvas { border: 1px solid #333; } | |
input[type="range"], input[type="checkbox"], button { margin: 5px; } | |
</style> | |
</head> | |
<body> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.2/p5.min.js"></script> | |
<script> | |
// Paste the entire p5.js code from above here | |
let particles = []; | |
let maxParticles, particleSize, speedLimit, trailLength, lifeSpan, gravityStrength; | |
let useMouse, chaosMode, bgOscillate, spawnRadius; | |
let baseHue, bgHueStart, bgHueEnd; | |
let controls = {}; | |
function setup() { | |
createCanvas(800, 600); | |
colorMode(HSB, 360, 100, 100, 1); | |
createControlPanel(); | |
resetSettings(); | |
for (let i = 0; i < maxParticles; i++) { | |
particles.push(new Particle()); | |
} | |
} | |
function draw() { | |
drawBackground(); | |
for (let i = particles.length - 1; i >= 0; i--) { | |
particles[i].update(); | |
particles[i].display(); | |
if (particles[i].isDead()) { | |
particles.splice(i, 1); | |
if (particles.length < maxParticles) particles.push(new Particle()); | |
} | |
} | |
if (bgOscillate) bgHueStart = (bgHueStart + 0.1) % 360; | |
drawNoiseOverlay(); | |
} | |
function drawBackground() { | |
for (let y = 0; y < height; y++) { | |
let inter = map(y, 0, height, 0, 1); | |
let c = lerpColor(color(bgHueStart, 20, 20), color(bgHueEnd, 50, 40), inter); | |
stroke(c); | |
line(0, y, width, y); | |
} | |
} | |
function drawNoiseOverlay() { | |
loadPixels(); | |
for (let i = 0; i < pixels.length; i += 4) { | |
let noiseVal = noise(i * 0.01, frameCount * 0.01) * 20; | |
pixels[i + 3] = pixels[i + 3] * (0.9 + noiseVal / 100); | |
} | |
updatePixels(); | |
} | |
function mousePressed() { | |
if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { | |
for (let i = 0; i < 20; i++) { | |
if (particles.length < maxParticles) particles.push(new Particle(mouseX, mouseY)); | |
} | |
} | |
} | |
class Particle { | |
constructor(x = width / 2, y = height / 2) { | |
let angle = random(TWO_PI); | |
this.pos = createVector(x + cos(angle) * spawnRadius, y + sin(angle) * spawnRadius); | |
this.vel = p5.Vector.random2D().mult(random(0.5, speedLimit)); | |
this.acc = createVector(0, 0); | |
this.hue = (baseHue + random(-30, 30)) % 360; | |
this.size = random(particleSize * 0.5, particleSize); | |
this.life = lifeSpan; | |
this.trail = []; | |
this.maxTrail = trailLength; | |
this.phase = random(TWO_PI); | |
} | |
update() { | |
let angle = atan2(this.pos.y - height / 2, this.pos.x - width / 2); | |
let orbitForce = createVector(cos(angle + PI / 2), sin(angle + PI / 2)); | |
orbitForce.mult(0.02); | |
this.acc.add(orbitForce); | |
if (useMouse) { | |
let mouse = createVector(mouseX, mouseY); | |
let gravity = p5.Vector.sub(mouse, this.pos); | |
let dist = gravity.mag(); | |
if (dist > 10) { | |
gravity.normalize().mult(gravityStrength / (dist * dist)); | |
this.acc.add(gravity); | |
} | |
} | |
if (chaosMode) { | |
this.acc.add(p5.Vector.random2D().mult(0.1)); | |
} | |
this.vel.add(this.acc); | |
this.vel.limit(speedLimit); | |
this.pos.add(this.vel); | |
this.acc.mult(0); | |
if (this.pos.x < 0 || this.pos.x > width) this.vel.x *= -0.9; | |
if (this.pos.y < 0 || this.pos.y > height) this.vel.y *= -0.9; | |
this.pos.x = constrain(this.pos.x, 0, width); | |
this.pos.y = constrain(this.pos.y, 0, height); | |
this.trail.push(createVector(this.pos.x, this.pos.y)); | |
if (this.trail.length > this.maxTrail) this.trail.shift(); | |
this.life -= 0.005; | |
this.phase += 0.1; | |
} | |
display() { | |
noStroke(); | |
for (let i = 0; i < this.trail.length; i++) { | |
let alpha = map(i, 0, this.trail.length, 0, this.life); | |
fill(this.hue, 80, 100, alpha * 0.5); | |
let trailSize = map(i, 0, this.trail.length, 1, this.size); | |
this.drawShape(this.trail[i].x, this.trail[i].y, trailSize * 1.5); | |
} | |
let pulse = sin(this.phase) * 0.3 + 1; | |
fill(this.hue, 80, 100, this.life); | |
this.drawShape(this.pos.x, this.pos.y, this.size * pulse); | |
} | |
drawShape(x, y, s) { | |
if (random() < 0.5) { | |
ellipse(x, y, s); | |
} else { | |
this.drawStar(x, y, s / 2, s, 5); | |
} | |
} | |
drawStar(x, y, radius1, radius2, npoints) { | |
let angle = TWO_PI / npoints; | |
beginShape(); | |
for (let a = 0; a < TWO_PI; a += angle) { | |
let sx = x + cos(a) * radius2; | |
let sy = y + sin(a) * radius2; | |
vertex(sx, sy); | |
sx = x + cos(a + angle / 2) * radius1; | |
sy = y + sin(a + angle / 2) * radius1; | |
vertex(sx, sy); | |
} | |
endShape(CLOSE); | |
} | |
isDead() { | |
return this.life <= 0; | |
} | |
} | |
function createControlPanel() { | |
let panel = createDiv().style('position', 'absolute').style('top', '10px').style('left', '10px').style('background', '#222').style('padding', '10px').style('color', '#fff'); | |
controls.maxParticles = createSlider(10, 500, 100, 10).parent(panel).input(updateSettings); | |
createP('Max Particles').parent(panel).style('margin', '5px'); | |
controls.particleSize = createSlider(5, 50, 15, 1).parent(panel).input(updateSettings); | |
createP('Particle Size').parent(panel).style('margin', '5px'); | |
controls.speedLimit = createSlider(1, 10, 5, 0.1).parent(panel).input(updateSettings); | |
createP('Speed Limit').parent(panel).style('margin', '5px'); | |
controls.trailLength = createSlider(5, 50, 20, 1).parent(panel).input(updateSettings); | |
createP('Trail Length').parent(panel).style('margin', '5px'); | |
controls.lifeSpan = createSlider(0.5, 2, 1, 0.1).parent(panel).input(updateSettings); | |
createP('Life Span').parent(panel).style('margin', '5px'); | |
controls.gravityStrength = createSlider(10, 200, 50, 5).parent(panel).input(updateSettings); | |
createP('Gravity Strength').parent(panel).style('margin', '5px'); | |
controls.spawnRadius = createSlider(0, 200, 50, 10).parent(panel).input(updateSettings); | |
createP('Spawn Radius').parent(panel).style('margin', '5px'); | |
controls.useMouse = createCheckbox('Mouse Reactivity', true).parent(panel).changed(updateSettings); | |
controls.chaosMode = createCheckbox('Chaos Mode', false).parent(panel).changed(updateSettings); | |
controls.bgOscillate = createCheckbox('BG Oscillate', true).parent(panel).changed(updateSettings); | |
controls.baseHue = createInput('#ff0000', 'color').parent(panel).input(updateSettings); | |
createP('Particle Hue').parent(panel).style('margin', '5px'); | |
controls.bgHueStart = createInput('#000033', 'color').parent(panel).input(updateSettings); | |
createP('BG Hue Start').parent(panel).style('margin', '5px'); | |
controls.bgHueEnd = createInput('#003366', 'color').parent(panel).input(updateSettings); | |
createP('BG Hue End').parent(panel).style('margin', '5px'); | |
createButton('Reset').parent(panel).mousePressed(resetSettings); | |
createButton('Randomize').parent(panel).mousePressed(randomizeSettings); | |
} | |
function updateSettings() { | |
maxParticles = controls.maxParticles.value(); | |
particleSize = controls.particleSize.value(); | |
speedLimit = controls.speedLimit.value(); | |
trailLength = controls.trailLength.value(); | |
lifeSpan = controls.lifeSpan.value(); | |
gravityStrength = controls.gravityStrength.value(); | |
spawnRadius = controls.spawnRadius.value(); | |
useMouse = controls.useMouse.checked(); | |
chaosMode = controls.chaosMode.checked(); | |
bgOscillate = controls.bgOscillate.checked(); | |
baseHue = hue(color(controls.baseHue.value())); | |
bgHueStart = hue(color(controls.bgHueStart.value())); | |
bgHueEnd = hue(color(controls.bgHueEnd.value())); | |
} | |
function resetSettings() { | |
controls.maxParticles.value(100); | |
controls.particleSize.value(15); | |
controls.speedLimit.value(5); | |
controls.trailLength.value(20); | |
controls.lifeSpan.value(1); | |
controls.gravityStrength.value(50); | |
controls.spawnRadius.value(50); | |
controls.useMouse.checked(true); | |
controls.chaosMode.checked(false); | |
controls.bgOscillate.checked(true); | |
controls.baseHue.value('#ff0000'); | |
controls.bgHueStart.value('#000033'); | |
controls.bgHueEnd.value('#003366'); | |
updateSettings(); | |
} | |
function randomizeSettings() { | |
controls.maxParticles.value(floor(random(10, 500))); | |
controls.particleSize.value(floor(random(5, 50))); | |
controls.speedLimit.value(random(1, 10)); | |
controls.trailLength.value(floor(random(5, 50))); | |
controls.lifeSpan.value(random(0.5, 2)); | |
controls.gravityStrength.value(floor(random(10, 200))); | |
controls.spawnRadius.value(floor(random(0, 200))); | |
controls.useMouse.checked(random() > 0.5); | |
controls.chaosMode.checked(random() > 0.5); | |
controls.bgOscillate.checked(random() > 0.5); | |
controls.baseHue.value(`#${floor(random(16777215)).toString(16).padStart(6, '0')}`); | |
controls.bgHueStart.value(`#${floor(random(16777215)).toString(16).padStart(6, '0')}`); | |
controls.bgHueEnd.value(`#${floor(random(16777215)).toString(16).padStart(6, '0')}`); | |
updateSettings(); | |
} | |
</script> | |
</body> | |
</html> |