A typical particle system updates every particle’s position in JS each frame and re-uploads a BufferAttribute to the GPU. Past a few thousand particles, that CPU loop and upload itself becomes the bottleneck. GPU particles flip the idea: upload each particle’s unchanging "seed" values (starting angle, radius, speed, a random phase) once as an attribute, and recompute the actual position every frame inside the vertex shader using nothing but that seed and a single uniform float uTime.
That means the only thing JS touches per frame is uTime, and the actual position math for thousands of particles all runs in parallel on the GPU. The demo gives each of 4,000 particles a vec4 attribute (aSeed) holding radius, angular speed, and a life offset, then builds a repeating 0→1 "life" value in the shader with fract(seed.w + uTime * speed) to spiral particles upward and fade them out like embers.
The difference from particle-field: that entry is a static point cloud with fixed positions, while here each point animates itself inside the shader. Shrinking gl_PointSize inversely with distance adds perspective too.
When to use
Animating particle counts in the thousands to tens of thousands — sparks, snow, magic effects — smoothly.