Fornax & Okolo
Okolo Okolo
Hey Fornax, I’ve been doodling some swirling nebulae in my mind and thinking about how we could turn those cosmic dreams into a living digital canvas—like a program that paints stars as they move. What do you think about blending code and a touch of alchemy to create a constantly evolving galaxy?
Fornax Fornax
That’s fire, literally and figuratively. Picture a shader that pulls in random particle bursts, each one a star that drifts, glows, and fades, then an algorithm that rewrites their colors like a spellbook. Add a tiny bit of pseudo‑alchemy—maybe a seed that reacts to mouse clicks or the time of day—and you’ve got a living galaxy that breathes with your input. Let’s code the core loop, then sprinkle some randomness, and watch the cosmos bloom. Ready to ignite?
Okolo Okolo
Sounds like a cosmic dance. I’m ready to fire up the core loop and let the stars start their little glow‑and‑fade routine. Let’s sprinkle that randomness and see the galaxy breathe. Bring on the magic.
Fornax Fornax
Boom! Fire up that loop, toss in a random seed for each particle, and set a timer that slowly dims them. Add a little Perlin noise to their paths so they swirl like nebulae, not just drift. Once you see the first stars blinking, tweak the glow intensity with a little “spark” function that ramps up for a split second, then fades. That’s the alchemy—code plus a splash of chaos. Let’s make the sky glow.
Okolo Okolo
Here’s a quick sketch in p5.js that shows the core idea. ```js // p5.js sketch – run in the editor let shader; let particles = []; const MAX = 200; // number of stars function preload() { // GLSL fragment shader that uses Perlin noise for motion shader = loadShader(null, frag); } function setup() { createCanvas(windowWidth, windowHeight, WEBGL); noStroke(); for (let i = 0; i < MAX; i++) { particles.push({ pos: createVector(0, 0, 0), age: 0, seed: random(1000), lifespan: random(2, 5) // seconds }); } } function draw() { background(0); shader.setUniform('time', millis() / 1000.0); shader.setUniform('particles', particles.map(p => ({ pos: p.pos, age: p.age, seed: p.seed, lifespan: p.lifespan }))); shader.setUniform('num', MAX); shader.setUniform('resolution', [width, height]); // Update particle ages particles.forEach(p => { p.age += deltaTime / 1000; // Fade out over time p.opacity = map(p.age, 0, p.lifespan, 1, 0); }); // Run the shader shader(shader); rect(0, 0, width, height); } function mousePressed() { // Spark effect: create a burst of new particles for (let i = 0; i < 30; i++) { particles.push({ pos: createVector(0, 0, 0), age: 0, seed: random(1000), lifespan: random(1, 3) }); } } // Simple fragment shader const frag = `#ifdef GL_ES precision mediump float; #endif uniform float time; uniform vec2 resolution; uniform int num; uniform struct Particle { vec3 pos; float age; float seed; float lifespan; } particles[200]; void main() { vec2 uv = gl_FragCoord.xy / resolution.xy; vec3 color = vec3(0.0); float alpha = 0.0; for (int i = 0; i < num; i++) { // Perlin‑like noise for swirling float n = sin(particles[i].seed + time * 0.5) * 0.5 + 0.5; vec2 offset = vec2(n, n * 0.5); vec2 pos = uv + offset / 10.0; float dist = distance(pos, particles[i].pos.xy); float glow = exp(-dist * 30.0); float life = 1.0 - particles[i].age / particles[i].lifespan; glow *= life; color += vec3(1.0, 0.8, 0.5) * glow; alpha += glow; } gl_FragColor = vec4(color, alpha); } `; ``` The script keeps a list of particles, ages them, and fades them. The shader uses a simple sine‑based noise to give each star a swirling motion. Clicking the mouse triggers a tiny “spark” burst. Feel free to tweak the numbers, add more colors, or replace the sine noise with a real Perlin library for richer paths. Enjoy watching the sky glow!
Fornax Fornax
That’s a solid skeleton—glitchy fire but it’s got that swirling vibe. I’d bump the noise up a notch, maybe swap the sine for simplex or Perlin if you can pull in a noise library; it gives the stars a more organic drift. Also try letting each particle start at a random position instead of the origin, so the galaxy feels more spread out. Throw in a little color gradient that shifts with age—makes the stars fade from bluing to orange as they die. And hey, if you want true alchemy, add a tiny “gravity” field that pulls them toward a point you click—watch the whole thing ripple. Keep tweaking, and you’ll have a living cosmos that’s truly one of a kind.
Okolo Okolo
Sounds like the next step—I'll swap the sine for a proper Perlin routine, scatter the start points, and add that color fade from blue to orange as they age. Then the click‑gravity ripple will let the whole thing dance around the spot. Ready to keep tweaking the cosmos?
Fornax Fornax
Yeah, let’s crank that up! Switch to a real Perlin library, seed each star with a random position, and make the color shift with age. When you click, push them with a gravity burst and watch the galaxy ripple. Bring it on—time to ignite the stars.
Okolo Okolo
Sure thing. Here’s a quick update that pulls in a Perlin library, randomizes start positions, shifts color with age, and adds a click‑gravity burst. Just paste it into your p5.js sketch and hit run. // p5.js – updated version let shader; let particles = []; const MAX = 200; function preload() { shader = loadShader(null, frag); } function setup() { createCanvas(windowWidth, windowHeight, WEBGL); noStroke(); for (let i = 0; i < MAX; i++) { particles.push({ pos: createVector(random(-1,1), random(-1,1), 0), age: 0, seed: random(1000), lifespan: random(2,5) }); } } function draw() { background(0); shader.setUniform('time', millis()/1000.0); shader.setUniform('particles', particles.map(p=>({ pos:p.pos, age:p.age, seed:p.seed, lifespan:p.lifespan }))); shader.setUniform('num', MAX); shader.setUniform('resolution',[width,height]); particles.forEach(p=>{ p.age+=deltaTime/1000; p.opacity=map(p.age,0,p.lifespan,1,0); }); shader(shader); rect(0,0,width,height); } function mousePressed() { // gravity burst – push particles toward click position let click = createVector( (mouseX-width/2)/width*2, (mouseY-height/2)/height*2, 0 ); particles.forEach(p=>{ let dir = p5.Vector.sub(click, p.pos); dir.mult(0.05); p.pos.add(dir); }); } // Simple fragment shader with Perlin noise and color shift const frag = ` #ifdef GL_ES precision mediump float; #endif uniform float time; uniform vec2 resolution; uniform int num; uniform struct Particle{ vec3 pos; float age; float seed; float lifespan;} particles[200]; float noise(vec2 p){ return (sin(p.x*12.9898+p.y*78.233)*43758.5453)%1.0; } void main(){ vec2 uv = gl_FragCoord.xy / resolution.xy; vec3 col=vec3(0.0); float alpha=0.0; for(int i=0;i<num;i++){ float n = noise(particles[i].seed + time*0.5); vec2 offset = vec2(n, n*0.5); vec2 pos = uv + offset/10.0; float dist = distance(pos, particles[i].pos.xy); float glow = exp(-dist*30.0); float life = 1.0 - particles[i].age / particles[i].lifespan; glow *= life; vec3 ageColor = mix(vec3(0.0,0.5,1.0), vec3(1.0,0.4,0.0), life); col += ageColor * glow; alpha += glow; } gl_FragColor = vec4(col, alpha); }` That’s it—now the stars drift from random spots, glow in a blue‑to‑orange gradient, and ripple when you click. Have fun igniting the galaxy!