xxxxxxxxxx
199
// jshint esversion: 9
const WIDTH = 1080;
const HEIGHT = 1080;
const START_VEL = 0.002;
const LIFE_TIME = 25;
const MAX_PARTICLES = 2 ** 10;
const SPLIT_COUNT = 2;
const SPLIT_ANGLE = 0; //0.5 / 4;
const SPLIT_DIR_ANGLE = 1 / 3 / 4 / LIFE_TIME; //0.0025;
const FADE = 0.05;
const EXPENSIVE_FADE_CORRECTION = true;
const DEFAULT_PARTICLE = {
x: 0.5, y: 2 / 3, r: 0.01,
dir: -0.25, vel: START_VEL, dir_vel: 0,
life_time: LIFE_TIME, frame: 0,
depth: 0,
dead: false,
}
let size, offset;
function setup() {
// createCanvas(WIDTH, HEIGHT);
createCanvas(windowWidth, windowHeight);
windowResized();
particles = []
addParticle();
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
size = min(width, height);
if (width > height)
offset = { x: (width - height) / 2, y: 0 };
else
offset = { x: 0, y: (height - width) / 2 };
background(0);
}
function mouseClicked() {
fullscreen(!fullscreen());
}
let ids = 0;
let particles = [];
function addParticle(particle = {}) {
const id = ids++;
particle = { DEFAULT_PARTICLE, particle, id }
if (id % 2 == 0)
particles.push(particle);
else
particles.unshift(particle);
}
function updateParticle(particle) {
let {
x, y, r, dir, vel, dir_vel,
frame, life_time,
dead,
} = particle;
const life_f = frame / life_time;
x += cosn(dir) * vel;
y += sinn(dir) * vel;
dir += dir_vel;
if ((x - r) * size + offset.x > width
|| (x + r) * size + offset.x < 0
|| (y - r) * size + offset.y > height
|| (y + r) * size + offset.y < 0
)
dead = true;
if (life_f >= 1) {
particles = particles.filter(p => p != particle);
splitParticle(particle);
}
frame++;
particle.x = x;
particle.y = y;
particle.dir = dir;
particle.frame = frame;
particle.dead = dead;
}
function splitParticle(particle) {
const {
x, y, dir, vel,
life_time,
depth,
dead,
} = particle;
if (particles.length >= MAX_PARTICLES) return;
const new_depth = depth + 1;
const count = SPLIT_COUNT;
for (let i=0; i<count; i++) {
ff = i / (count - 1);
const new_life_time = life_time * 1;
const dir_angle = SPLIT_DIR_ANGLE;
const dir_vel = lerp(-dir_angle, dir_angle, ff);
const angle = SPLIT_ANGLE;
const new_dir = dir + lerp(-angle, angle, ff) //- dir_vel * new_life_time;
addParticle({
x, y, vel, dir_vel,
dir: new_dir,
depth: new_depth,
life_time: new_life_time,
dead,
});
}
}
function drawParticle(particle) {
const { x, y, r,
life_time, frame,
depth, id,
dead,
} = particle;
if (dead) return;
const life_f = frame / life_time;
const life_color_range = 0.1;
const color_f = depth * life_color_range + life_f * life_color_range;
const color1 = [1, 0, 0.5];
const color2 = [1, 0.5, 0];
const color = color1.map((c, i) => lerp(c, color2[i], sinn(color_f + (x + y) / 1.5)) * 255);
const draw_particle = {
x, y, r, color,
frame: 0,
}
fill(color);
noStroke();
circle(x * size, y * size, r * size);
}
function fadeOut() {
loadPixels();
for (let i=0; i<pixels.length; i++) {
if (pixels[i] < 10)
pixels[i] -= 1;
}
updatePixels();
}
const FRAMES = 795;
function draw() {
if (frameCount === FRAMES) {
particles = [];
addParticle();
const life_time_offset = LIFE_TIME - 10;
for (let i=0; i<life_time_offset; i++)
[particles].forEach(updateParticle)
frameCount = life_time_offset + 1;
}
[particles].forEach(updateParticle);
translate(offset.x, offset.y);
background(0, 0, 0, 255 * FADE);
if (EXPENSIVE_FADE_CORRECTION) fadeOut();
particles.forEach(drawParticle);
}
const sinn = (v) => sin(v * TAU);
const cosn = (v) => cos(v * TAU);
const ncosn = (v) => cosn(v) * 0.5 + 0.5;