Skip to content
animorio
IT
All components

The iron filings nav

Navigation, Physics, HoverCanvasAdvancedCompressed weight: Demo 7.0 KBno librariesFreeDownload the zip

A row of links on a pale sheet strewn with thousands of thin iron filings. Under the current link there is a hidden magnet: the filings around it line up along its field and draw the curves between its two poles around the word. Pointing at another link the field moves there and every filing turns on its own spring, a little later the further away it is.

The code

A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>The iron filings nav</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/instrument-sans@5.3.0/index.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="stage">
    <!-- the nav: a pale sheet strewn with iron filings, and a magnet hidden under the current link. The filings line up
         along its field and draw the curves between its two poles around the word; pointing at another link the
         field moves there, and every filing turns on its own spring -->
    <nav class="ff" aria-label="Main" data-nav>
      <canvas class="ff__field" aria-hidden="true" data-still></canvas>
      <canvas class="ff__field" aria-hidden="true" data-field></canvas>
      <ul class="ff__list" data-list>
        <li><a class="ff__link" href="#" aria-current="page" data-link><span class="ff__word" data-word>Work</span></a></li>
        <li><a class="ff__link" href="#" data-link data-autoclic><span class="ff__word" data-word>Studio</span></a></li>
        <li><a class="ff__link" href="#" data-link data-autoclic><span class="ff__word" data-word>Process</span></a></li>
        <li><a class="ff__link" href="#" data-link data-autoclic><span class="ff__word" data-word>Journal</span></a></li>
        <li><a class="ff__link" href="#" data-link data-autoclic><span class="ff__word" data-word>Contact</span></a></li>
      </ul>
    </nav>
  </main>

  <script src="script.js"></script>
</body>
</html>

Playground

Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.

18 values to change

Or ask Claude Code for it

With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:

Take “The iron filings nav” from Animorio and fit it into my site

What it does

On a white background a paper-coloured sheet with rounded corners and a row of links in the middle: Work, Studio, Process, Journal and Contact, grey except the current one, black. The whole sheet is strewn with thin iron filings, lying every which way and a little different in length. On arrival a magnet switches on under Work: a wave spreads from the word and the filings nearby turn, darken and move a little towards the poles, until they draw the classic curves of a magnet, leaving one end of the word, looping above and below it and coming back in at the other end; at the two ends the filings fan out like rays. Pointing at another link with the mouse, or reaching it with the Tab key, the field moves there: the wave starts from the new word, the filings around the old one go back to lying loose and pale, those around the new one line up, each on its own spring, so the filings swing a little before they stop. Leaving the row the field goes back to the current link; clicking, it stays on the new one. On a phone a finger on a link is enough to move the field, and lifting it chooses the link. When everything is at rest the drawing stops.

How it works

The filings on the sheet

The filings lie on a grid with a step of SPACING pixels, each shaken out of place by nearly a whole step, so they cover the sheet evenly without looking set in rows. Each has its own resting angle, length and stiffness, taken from a seeded random generator, the same at every load.

The field of a dipole

For every link, once, the field of two poles placed just before and just after the word is worked out: the sum of r/|r|³ towards the north pole and the opposite towards the south pole, softened a little so it never goes to infinity. The strength becomes a weight w = 1 − e^(−|E|·REACH³/pole distance): where the field is strong the filing takes its direction, where it is weak it keeps its own angle, and the two angles are mixed taken twice, since a filing has no head or tail.

Denser and darker near the poles

Besides the angle, every field gives every filing a shift towards the nearer pole, at most GATHER pixels and never past the pole, and a shade that grows with the field. On the words the filings stay pale, and the words have a halo the colour of the sheet, so the letters are always legible.

Each on its own spring

Every frame each filing's angle is pulled towards the field's by a damped spring (SPRING and DAMPING, the shortest way round modulo 180 degrees), its position by a softer spring, its shade by an exponential approach. When the field changes, each filing starts following the new one when a wave reaches it, spreading from the word at WAVE pixels a second, so the near ones turn before the far ones. The step is at most 1/30 of a second.

Drawing thousands of filings

All the filings with the same shade go in one path and one stroke, seven in all. At the start of every change the filings that will not move (the two fields agree and they are still) are drawn once on a still canvas; every frame only the others are worked out and drawn, on a second canvas above. When everything has been still for a quarter of a second the loop stops and the still canvas takes them all.

Values to change

NameFileDefaultWhat it changes
SPACINGscript.js8How far apart the filings lie, in pixels: less makes more of them.
LENGTHscript.js7How long a filing is, in pixels.
REACHscript.js118How far from the word the field still lines the filings up, in pixels.
SPRINGscript.js110How stiff the spring that turns each filing is.
DAMPINGscript.js8How quickly a filing stops swinging: less makes it overshoot more.
WAVEscript.js900How fast the change of field spreads across the sheet, in pixels a second.
GATHERscript.js9How far the filings slide towards the poles, in pixels.

Try them in the Playground

When to use it

For the nav of a design, architecture or engineering studio, a lab, a science magazine or the portfolio of someone who works with physics and materials.

On phones

The sheet takes the width of the screen and the links shrink down to 15 pixels; the filings get denser and shorter in proportion. A finger on a link moves the field at once, lifting it chooses the link, with no wait for a double tap.

With reduced motion

No wave and no springs: the filings are already lined up around the current link and, pointing at or choosing another link, they are drawn at once in the new pattern.

Pitfalls

  • A filing has no direction: 10 degrees and 190 are the same thing. The gap between its angle and the field's must be brought between −90 and 90 degrees, or half the filings would make a half turn for nothing; and to mix the field with the resting angle the angles are mixed taken twice.
  • With the canvas drawn by the graphics card, thousands of thin, semi-transparent strokes every frame were very slow on some machines: getContext('2d', { willReadFrequently: true }) keeps the canvas in memory and has the processor draw it, which is quicker with many small strokes.
  • Working out the field every frame cost too much: it is worked out once per link (angle, shade and shift of every filing) and changing link only means changing which table to follow.
  • Redrawing the whole sheet every frame was pointless, since away from the words the filings do not move: the still filings go on a canvas of their own drawn once, and the live canvas has a layer of its own (will-change), so the sheet, its shadow and the halos of the text are not repainted.
  • The current link does not change font weight: with a variable font the word would widen, the poles would no longer be at its ends and the field would have to be worked out again halfway through the animation.

Libraries

Instrument Sans (font variabile) 5.3.0.

Compressed with gzip, the three demo files weigh 7.0 KB, and no libraries are needed.

Testing

Tested on 5 October 2026

  • Desktop: Done
  • Phone: Done
  • Reduced motion: Done
  • Safari on iPhone: Done

License

Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.

All components