Magnetic fields in canvas and Pixi.js
Visualising a bar magnet's field with sprite "iron filings" driven by a physics equation in JavaScript.
We all remember playing with magnets as kids. One popular experiment to show how magnets work uses iron filings suspended on a sheet of paper held above a bar magnet.
This gives a good visualisation of the size and placement of the magnetic fields surrounding the magnet.
This demo a simple little demo to show how mathematical functions can be applied to achieve relatively complex effects rendered with javascript and HTML <canvas> elements
2026 update The CodePen embed is being re-hosted here; the interactive version will return.
Here you can see an initial attempt to render the effects of a magnetic field by introducing “iron filings” – which are actually just image sprites rendered with the Pixi.js library and animated using a mathematical function.
There are still a lot of features that I hope to eventually implement, to create more realistic behaviour (listed below).
For reference, here’s an image of the classic “bar magnet with iron filings” experiment which shows the iron filings aligning along the lines of the magnetic fields:
For those who may be interested, I found reference to the appropriate equation in a physics textbook and when written in Javascript, it looks a little something like:
var B = (Math.pow(10, -7) * Math.sqrt(1 + 3 * Math.pow(Math.cos(angle), 2))) / Math.pow(distance/1000, 3);
Now, I’m certainly no mathematician. In fact, I’d class myself more as an engineer (i.e. definitely not a mathematician) but it seems like the above formula does the trick, and generates something that looks like it probably works as a magnetic field simulation. To the engineer part of my brain, that’s good enough.
From my understanding, the formula above will estimate the magnetic field strength at a given point, but I was trying to simulate a bar magnet (i.e. made up of a large number of individual magnetic points). So, to achieve that, I calculated the field strength at multiple points on the “magnet”, and then from that derived an average. Again, this may not be strictly the right approach, but it seems to work.
There’s plenty more to do here though:
Heads up This predates Pixi v8. The Pixi API has changed shape: Application now initialises asynchronously, so the old synchronous new PIXI.Application({...}) constructor pattern won’t give you a ready renderer.
const app = new Application();
await app.init({ resizeTo: window, antialias: true });
document.body.appendChild(app.canvas);
The “computationally expensive” per-filing field maths is also a natural fit for a fragment shader now — compute the field direction per pixel on the GPU (Pixi v8’s Filter / mesh shaders, WebGL or WebGPU) and the whole-screen field becomes cheap, sidestepping the per-sprite averaging entirely.
I help content-rich organisations understand their data and pull it back into one place. Tell me what specific problems you're having and I'll be happy to talk solutions with you.
Tell me what specific problems you’re having and I’ll be happy to talk solutions with you.