04Object 04 · Surfaces
Ferrofluid
Ferrofluid in a dish. It gathers toward the pointer and erupts into sharp spikes, then melts back into a trembling puddle. Your pointer is the magnet.
- Version
- 0.1.0
- Size
- 32.4 KB gzipped
- Access
- With a Pass
- Needs
- ferrofluid.mjs + ferrofluid.css
- Tests
- 35 tests · 12 states
Use it
A hero, a cover or an empty state that a visitor plays with before reading anything: a real material responding to their hand, lit like a product photograph, that sleeps and costs nothing when left alone.
Copy the ferrofluid folder from its package next to your page, link its stylesheet and construct it on an element. Every option has a default; the lab’s Code tab writes the same example at any settings, and for React, Vue, Svelte or a custom element (Using a framework).
<link rel="stylesheet" href="ferrofluid/ferrofluid.css">
<div id="ferrofluid" style="width: min(94vw, 1100px); height: min(70vh, 520px); border-radius: 16px; overflow: hidden; background: #d8d4cc"></div>
<script type="module">
import Ferrofluid from './ferrofluid/ferrofluid.mjs';
const ferrofluid = new Ferrofluid(document.getElementById('ferrofluid'), {
strength: 1,
density: 13,
sharpness: 0.7,
});
// ferrofluid.update({ … }); change any option in place
// ferrofluid.destroy(); and take it away again
</script>Options
| Option | Type | Default | What it does |
|---|---|---|---|
| strength | number, 0.4 to 1.6 | 1 | How far the field reaches. Past the threshold the surface erupts; a stronger magnet raises more of the pool. |
| density | number, 8 to 22 | 13 | Spikes across the resting pool: the lattice spacing. |
| sharpness | number, 0 to 1 | 0.7 | 0 is soft rounded bumps; 1 is tall needles with a fine point. |
| volume | number, 0.6 to 1.4 | 1 | Fluid volume |
| viscosity | number, 0 to 1 | 0.4 | How it settles. Thin fluid springs up and wobbles; thick fluid oozes. |
| vessel | dish · plate · free | 'dish' | A shallow dish, a wide plate, or free on the backdrop. |
| finish | steel · brass · graphite · bone | 'bone' | Glazed bone ceramic, polished steel or brass, anodised graphite. |
| light | number, 0 to 345 | 315 | 0 is from above, clockwise. |
| idle | boolean | false | A virtual magnet circles slowly when no pointer is near, for a hero that is never still. It never sleeps while visible. |
| intro | boolean | true | A magnet passes over the pool once, when it first comes into view. |
| quality | auto · low · high | 'auto' | Auto renders at 85% of device pixels and drops if frames run long. Low is for weak machines; high is full resolution. |
| label | text | '' | What a screen reader hears. Empty describes the pool and its vessel. |
Methods
new Ferrofluid(element, options)- Builds it inside the element with these options.
update(opts = {})- Change options in place.
magnetAt(x, y, strength = 1)- Hold a magnet at a point given as fractions of the element (0…1).
release()- Take the magnet away; the spikes melt back.
replay()- Run the opening pass again.
listen(source)- Let sound drive the magnet.
unlisten()- Stop listening: a microphone's tracks stopped and its audio context closed; a page's node disconnected.
listeningstatestats- What the renderer is doing, for a page that wants to show it (or a test).
frame()- Draw the current state now, synchronously.
destroy()- Stops it and cleans up after it.
States
- At restA smooth black puddle in its dish, reflecting the studio; the loop is asleep and costs nothing.
- Opening passOnce, when the pool first comes into view, a magnet passes over it: the fluid gathers, erupts and melts back.
- Magnet nearThe fluid leans and flows toward the pointer, heaps under it, and past the critical field erupts into spikes on a hexagonal lattice, tallest under the magnet and leaning toward it.
- ReleasedThe field fades on a slower spring; spikes survive down to a lower threshold, collapse with a wobble, and the surface trembles with fine rings that die away.
- Idle orbitWith idle on, a virtual magnet circles slowly when no pointer is near, so a hero is never still. It pauses off screen.
- ListeningAfter a click on a microphone button, spike height follows the room's loudness. Stops, with every track released, on unlisten or destroy.
- Off screen or hiddenThe loop pauses; a returning tab cannot launch the springs with a long frame.
- Reduced motionOne still frame of the spiked state under a centred magnet, on the first paint. No frames after it.
- Software rendererDetected at start-up: instead of a slideshow, one full-resolution, anti-aliased still is built up in strips without blocking the page.
- CompilingThe shader compiles in the background; the page is usable at once and the fluid fades in when its first frame is ready.
- No WebGL2A 2D drawing of the spiked pool in its dish, lit from the same lamp as the shader; the text alternative says it is a still.
- Context lostThe loop stops and waits; when the context is restored the shader is rebuilt and the frame redrawn.
How it works
Made of: Sdf raymarching, Rosensweig threshold, Hysteresis, Hex spike lattice, Damped particle body, Spring magnet, Procedural studio lighting, Adaptive render scale, Sleeping loop, Audio reactive.
Original. Taken from the physical Rosensweig instability and from product photography of ferrofluid, not from a catalogue reference, so references is honestly empty. WebGL2 raymarching with no library; the studio, the dish and the fluid are all procedural, so no image ships.