Repository navigation
Releases: stoatworks-labs/ferrofluid
Release list
Ferrofluid v0.1.0
The first release of Ferrofluid: ferrofluid spikes on the beat, for Resolume Arena and Avenue, as two FFGL plugins. SW Ferrofluid (FE01) is a source: a dish of ferrofluid over an electromagnet, in a photographer's studio. SW Ferro Over (FE02) is an effect: the same pool, seen from above, with your clip on a screen hung over it and broken up in the fluid's mirror.
The one idea: a pool of ferrofluid over an electromagnet whose current is the music. Ferrofluid is oil full of magnetite particles about ten nanometres across. Push the field past a critical value and the flat surface can't hold: it stands up in spikes, all at once, on a hexagonal lattice about a centimetre apart. That's the Rosensweig instability (Cowley and Rosensweig, 1967), and nothing in the plugin draws a spike where it likes. The pool's surface follows the linear theory exactly, mode by mode, so the spikes come up at the speed that much drive gives, at the critical wavelength however loud it gets, outward from the middle of a coil. The onset is subcritical, so once up they hang on until the current falls to the fold (7% below onset for EFH1), which is why the default Bias keeps them standing between kicks. Each spike is drawn as that fluid's own equilibrium spike at the field it stands in, solved offline with its real magnetisation curve, gravity and surface tension: round and low just past onset, a sharp cone with a concave skirt at the top of the drive. The fluid is a black mirror, about 4.5% reflective, so what you see is what it reflects: the studio's lights in the source, your clip in the Over, and every spike's neighbours spreading from its base.
Controls: Fire On (Off, Beat, Half Beat, 2 Beats, Bar, Onset), Fire, Audio, Band, Gain and Bias (in critical currents, 0–1.5), Coil Lag (the coil's L/R, 1–300 ms), Threshold, Pulse; Magnet (Uniform, a Helmholtz pair; Coil; Three Coils, one per band), Coil Size, Coil Spread (2–10 cm); Fluid (Ferrotec's EFH1, EMG 901, EMG 909), Viscosity, Noise, Settle; Field Width, Tilt (0–60°), Exposure; the source adds Lights (seven set-ups) and Backdrop, the Over Height (the screen above the pool) and Mix.
Downloads: a universal macOS build (Apple silicon and Intel) as a .dmg or .zip, and a Windows x64 installer (-setup.exe) or .zip. Each carries both plugins: Ferrofluid.bundle and Ferrofluid Over.bundle on macOS, Ferrofluid.dll and Ferrofluid Over.dll on Windows. The macOS build is Developer ID-signed and notarised by the fleet's signing agent once the release is published. The Windows build isn't signed, so SmartScreen warns once.
What is measured (offline, by tools/verify.sh on an Apple Silicon Mac under macOS 26, driving the plugins' own classes in a headless GL context at 1280×720 and 320×180, and four checks again on Apple's software renderer):
- The instability. Every mode of the surface grows or rings at the Cowley–Rosensweig rate to 1.3e-5 of its height. In the Helmholtz pair EFH1's flat pool is still at 12.003 A and grows at 12.033 A, against the theory's 12.018 A, and the harness reproduces Mahr and Rehberg's measured critical field (5.9 kA/m). The settled lattice sits at the critical wavelength, from the heights and from the picture, with three peaks 60.7°, 56.1° and 63.2° apart.
- The spikes. The offline solver matches the fit to Gollwitzer et al.'s X-ray measurements of a real pattern to within 1.1% in amplitude. A lattice of the pool's spikes at equilibrium is the solver's cell to 9.5e-4 of the peak; EFH1's tip at 1.5 I_c is 0.18 mm solved and 0.19 mm drawn.
- The coil. Its field against Biot–Savart summed by hand; the L/R lag exact; the patch's edge where the local magnetisation crosses the critical one, to a spike's spacing; and, new in this release, Three Coils at the top of Coil Spread fits the pool for every fluid.
- The light and the rest. Each pixel's reflectance against the exact Fresnel formula for the fluid to 5.5e-7; the Over at Mix 0 returns the clip bit for bit; every beat's pulse starts within 1.8e-15 s of its beat; a resize leaves the pool 0 bytes different; both plugins hand back the GL state they were given.
- The checks can fail. Twenty-one deliberately wrong models each fail their check, and seventeen one-character mutants of the shipped GLSL and C++ are all caught. All 20 controls of each plugin that have pixels change the picture. The bundles are universal, and
oxbowseesSW Ferrofluid/FE01/ source andSW Ferro Over/FE02/ effect, 26 parameters each, and renders through both.
In Resolume Arena 7.28.1 on macOS, driven over Arena's REST API: both plugins register and render. Of the source's 21 controls, the 18 that don't need sound all change Arena's output, Fire On follows Arena's beat, and the Over's controls do the same over a frozen lattice, with Mix 0 bit for bit the clip with the effect bypassed (0 of 2,073,600 pixels different). No sound reached it there, so Audio, Band and Threshold are untested in a host.
On Windows, in Resolume Arena 7.27.1 (win-lab, Mesa llvmpipe: software rendering, no GPU, no sound device), on this release's own ferrofluid-windows-x86_64.zip: both plugins load and register (FE01 source, FE02 effect), with every parameter as declared. SW Ferrofluid renders and passes the fleet's Arena checks: Backdrop, Exposure, Field Width, Fluid, Lights, Tilt and Viscosity measurably change a still frame, the other nine controls were too close to call against a pool that never holds still, and none was dead; the three audio controls can't be tested without a sound device. SW Ferro Over couldn't be measured: Arena's capture came back black for the bare clip under it as well, so that run says nothing either way about the Over's picture on Windows. The pool ran Arena at about 0.1 fps there, which says nothing about speed on a GPU.
Fixed before release. Coil Spread ran to 30 cm, and past about 10 cm the far coil's patch was cut off in a straight line at the pool's edge, since the pool repeats and the coils' field doesn't. It now stops at 10 cm, with a check that fails at the old range.
What isn't verified, or is a limit. Where the spikes stand and how far they've grown is still a chosen model (the pattern engine), fitted to the solver; only their shape is solved, and a growing spike is the equilibrium one scaled, not the real dynamics. Over a coil held steadily past onset (1.125–1.3 I_c) the patch lays down as stripes rather than hexagons, drawn as rows of spikes, which no real stripe looks like; at the defaults, and in the Helmholtz pair, it's hexagons. A Fire press from a pool held below the hysteresis loop needs a longer Pulse or more Gain to show (the guide has a table). The fluids' optical constants are assumed. No GPU but one Mac's has run it, and the audio controls have never heard real music in a host.
Cost: median GPU frame time at the defaults, on an Apple Silicon GPU shared with other work tonight: the source 6.2 ms at 720p and 1080p and 9.6 ms at 4K, the Over 7.1, 9.0 and 18.8 ms. Most of it is the pool, about 150 passes a frame whatever the raster. Nothing was timed inside Resolume.
Not done. No presets and no OpenFX port. The browser demo runs the plugin's own shaders over a JavaScript port of its CPU half, with no audio, and says so.
- User guide: https://stoatworks-labs.com/software/ferrofluid/guide/
- Project page: https://stoatworks-labs.com/software/ferrofluid/
- Browser demo: https://ferrofluid-demo.stoatworks-labs.com