Activity

onionwit

Shipped this project!

Hours: 18.97
Cookies: 🍪 510
Multiplier: 26.89 cookies/hr

This project comes to a close, and I must say, I do adore it. It’s really fascinating, and I could genuinely sit for hours just watching those little particles float around and just evaporate. I’ve learnt a lot throughout this project, deepening my threejs skills, and 3d web dev. I hope you enjoy this project just as much as I did and hope you’re nice to it when voting :).
That’s it! 😊

onionwit

Added a settings menu, reset button and mouse cursor repulsion for a bit of interactivity. For a bit of fun, I also added user-uploaded image support
Here’s how it works:
Settings Menu:
The sliders in the settings panel directly modify parameters (called “uniforms”) that the GPU shader programs use. When you move a slider, JavaScript updates a value in GPU memory like particle size, repulsion radius, or decay speed. The next frame, the shader reads these new values and immediately changes behavior.

Reset Button:
Every particle remembers its “home” position from the original image grid. That position is stored in a texture as the initial state. When you click reset, the simulation shader reads from that stored texture instead of the current animated positions, snapping every particle back to where it started. The “life” value also resets to full, so particles fade back in smoothly.

Mouse Cursor Repulsion:
Each frame, JavaScript captures your cursor position and converts it to the 3D scene’s coordinate space, then sends that position to the GPU as a uniform. In the simulation shader, for every particle (texel), it calculates the distance to the cursor. If the particle is within the “repulsion radius,” it applies a force pushing the particle away.
That’s it!

Attachment
0
onionwit

Today, I got the main bulk of the project done - PARTICLE GEOMETRY!

Here’s how it works:
Instead of storing particle positions in CPU arrays and updating them each frame, the positions are stored in a texture (one texel per particle). This texture holds the (x, y, z) position and a “life” value in RGBA channels.

Each frame, a fullscreen compute pass (a small quad render) reads the current texture and writes an updated texture, moving each particle by adding Perlin noise (for organic wandering). If a particle’s life decays to zero, it resets to its original image-grid position. This all happens on the GPU in parallel.

When it’s time to draw, the particle geometry is simple: one vertex per pixel, but no position data. Instead, each vertex carries a UV coordinate that points into the simulation texture. The vertex shader samples that texture to fetch the particle’s current (x, y, z), transforms it to screen space, and scales the point size based on life. The fragment shader colors each point by sampling the original image using the per-pixel image UV.

The result: thousands of points move smoothly via GPU simulation, each one retains its source pixel color, thus creating fluid motion.

That’s it! ;)

Attachment
0
onionwit

Managed to take an image, and split it up into particles, and started on the particle geometry. Right now, I’ve only got each particle vibrate slightly.

Here’s how it works:
I treated the image (scaled down for performance) as a grid of pixels, and created one point per pixel. For each pixel, a 2D position is calculated on a normalised plane where x,y ∈ [-0.5, 0.5] and z = 0.
FOR EACH POINT, I store:
a) an image UV pointing back to that pixel, so I can fetch its colour later
b) a size multiplier
c) a UV into a simulation texture that holds the particles position
This allows for more GPU-friendly play. During rendering, the vertex shader samples the simulation texture using the per-point UV to get the current position, and the fragment shader samples the image using the image UV to colour the point, so the original picture appears as a cloud of coloured particles. Ta-da

Thats it!

Attachment
0
onionwit

First work session!
Started off simple with a title screen (its amazing what you can do with big letters and a nice font).
I also started work on the user image upload. Got a nice UI going with that creamy beige colour. I have a simple flow animation going on, but definitely needs to be iterated over in future sessions. That’s it.

Attachment
0