How I Got a Particle Flow Field to Run at Near-Zero CPU
A behind-the-scenes look at building Perlin Flow Fields — how thousands of particles trace a noise field on the GPU, and the specific choices that keep it off your CPU and easy on your battery.
Perlin Flow Fields is deceptively busy. Thousands of particles drift across the screen at once, each following invisible currents, and when people see it their first assumption is that it must be hammering the machine. It isn't — it's one of the lighter things I've made. I thought it'd be worth writing down why, because it's a nice illustration of a general principle: performance is usually about where the work happens, not how much of it there is.
What you're looking at
A flow field is a grid of directions. At every point on the screen there's an arrow, and the arrows vary smoothly because they're driven by Perlin noise — the same kind of soft, organic randomness used for clouds, terrain, and smoke in games. Drop a particle onto that field and it follows the arrows, curving as they curve. Drop thousands in and you get those flowing, current-like streams.
Perlin Flow Fields running sparse, the way I keep it. See it in the marketplace →
The wallpaper exposes the parts worth playing with: Flow Speed, Line Density, Intensity, and two colours — Color A and Color B — that the streams blend between. Turn density up and it becomes a dense weave; turn it down and it's a few lonely threads. I run it sparse.
The expensive way to build this
The obvious approach is to loop over every particle on the CPU, every frame: read the noise at its position, work out the new direction, move it, repeat — thousands of times, sixty times a second. That's a lot of CPU work, and CPU work is exactly what heats a laptop and drains a battery. Build it this way and you get the busy, fan-spinning wallpaper everyone assumes this must be.
The cheap way
So I don't do the work there. The particles live and move on the GPU — the chip built to do the same small calculation to thousands of things at once, which is precisely this problem. Instead of the CPU stepping through particles one by one, the GPU nudges them all essentially in parallel. The noise field itself is computed in a shader rather than sampled from a table. The CPU's job shrinks to almost nothing: it kicks off the frame and gets out of the way.
Same visible result — thousands of particles flowing — but the load sits on the chip that shrugs it off instead of the one that would sweat. (If that CPU-vs-GPU split is new to you, I laid it out properly in GPU-accelerated wallpapers, explained.)
The two boring wins on top
Cleverness aside, two unglamorous choices do a lot of the heavy lifting:
- A 30 FPS default. Ambient motion doesn't need 60. Running at 30 FPS by default roughly halves the work for no visible loss (with an FPS choice in settings), and for something this diffuse you genuinely can't tell.
- Pause when hidden. Maximise a window over it and the whole thing stops rendering. On a normal work day that's most of the time, and it costs literally nothing while it's out of sight.
Put together, that's how a wallpaper that looks like it should be expensive ends up being one of the cheapest to run.
See it move
Screenshots don't do it justice — the whole appeal is the motion.
If you like the idea of generated-not-filmed scenes, Ignis: Solar Flares is built on the same principle, and the rest of the collection mostly is too.
Related articles
Space & Astronomy Live Wallpapers: Real-Time vs Video Loops
Deep space is the ultimate live wallpaper theme. Here is why real-time GPU rendering beats video loops for space backgrounds, plus four flagship scenes.
3 min readDoes a Live Wallpaper Drain Your Mac's Battery?
The honest answer is 'it depends what kind' — so here's what actually costs battery in a live wallpaper, and what doesn't, from someone who has spent a lot of time measuring it.
3 min readGPU-Accelerated Wallpapers, Explained (and Why They Beat Video Loops)
'GPU-accelerated' gets thrown around a lot. Here's what it actually means for a live wallpaper — and why a WebGL scene and a looping video behave so differently even when they look similar.
3 min read