I made hairline, a set of six small line drawings that move when your pointer passes over them. People ask how they’re made, so here’s how, roughly in the order I work: the still picture, the lines, the movement, and a couple of bugs worth avoiding.
There are eleven figures on this page, and every one of them is live, starting with this one.
Start with the still picture
Most people who see one of these drawings will never move a mouse over it. They see it in a screenshot, in a preview, or on a phone. So the version nobody touches has to work on its own, and that’s where I start.
The cards above lean back as if someone just put them down. The field of pillars below rests as a small dune. Once the still picture looks right, I decide what the pointer should do to it. When the pointer leaves, the drawing goes back to exactly that picture.
Fewer lines
The drawings are thin lines, redrawn many times a second from a small 3D model and always seen from the same angle, where an edge climbs one step for every two steps across. It’s the angle Linear uses for the illustrations on its site, which is where I got the style.
Most of the look comes from what’s left out. Corners are rounded, so the shapes read as objects rather than diagrams. Vertical edges aren’t drawn at all: the outline carries the shape, with one faint line inside to suggest the top. There’s one line weight and no colour, so the only way to highlight something is to make its line brighter. And there are no words inside a drawing, only around it.
Two kinds of movement
A hover animation has two different jobs, and most of them feel off because they use the same kind of movement for both.
One job is choosing, like moving from one card to the next. That’s a short trip with a known start and end, so a timed animation fits: it runs for a set time along a planned path.
The other is following your hand, which moves a little on every frame. The common approach restarts the timed animation each time the pointer moves. But timed animations start gently, and restarting one constantly keeps it stuck at the gentle start. The drawing lags behind and only catches up after you stop.
For following, I use a spring. Think of a ball tied to your finger with a rubber band. When your finger changes direction, the band just pulls a different way, and the ball keeps moving.
The spring
A spring has two settings. Stiffness is how hard it pulls toward its target. Damping is what slows it down, the way honey slows a spoon.
Damping is what changes how it feels. With too little, the spring overshoots and wobbles. With too much, it crawls in. Somewhere in between, it gets there quickly and stops.
More damping doesn’t feel calmer, just slower: the back puck takes about twice as long to stop as the second one. That second one is the setting every hover in hairline uses. It goes past the line by less than a tenth of a percent, which is too little to see but enough that it lands softly instead of stopping dead.
The same on every screen
Screens redraw at different speeds: 120 times a second on some, 60 on most, sometimes 30 on a busy laptop. And when you switch back to a tab after a while, the first redraw can arrive a third of a second late.
If the spring takes one jump per redraw, it moves a little differently on each of those, and after a long pause it can shoot to nine times its target. So each redraw is split into many small steps of the same size instead. The spring then follows the same path everywhere, and a faster screen just shows more of it.
A spring also knows when it’s finished. Once it’s close enough and slow enough, it lands exactly on its target and stops asking for redraws. I’ll come back to why that matters near the end.
Bounce
A bounce is movement that goes past its mark and comes back. It suits things you put energy into, like a flick. It doesn’t suit a hover, because your pointer just arrives. A card that wobbles when you point at it is reacting to a push you never gave, so hairline’s hovers stop just short of a wobble.
The turntable below is the one figure where you can throw something. You can spin it with your hand, and it slows down in two stages. First it coasts, losing speed to friction the way a record does after you let go, quickly at first and then gently. Then, once it’s turning slowly and your hand has stopped, a spring pulls it to the nearest quarter turn ahead of it. It never picks the one behind, so it never reverses.
That second stage is why every spin stops on the angle I drew it for.
Fast start, slow finish
When you choose something, the timed animation runs for 0.7 seconds. That sounds slow, but most of the movement happens right away: two thirds of the distance in the first seventh of a second, so it feels immediate. The rest is a long, soft landing.
The usual default starts slowly, speeds up and slows down again. In its first fifth of a second it barely moves, and that reads as lag. Once someone has made a choice, the movement shouldn’t hesitate.
If the target changes halfway, the movement starts over from wherever it is, so nothing jumps. And if someone has turned on reduced motion on their device, everything arrives at once.
Ripples, not queues
When many parts move at once, the order matters. If they start one by one from the first, the movement always runs down the row from the same end, wherever you pointed. Starting from the part you touched and spreading outward reads as one gesture, like a ripple. The wait between parts has to stay short, though, or the last one starts after the first has already finished.
How far the movement spreads matters too. The field below lifts the pillars nearest your pointer the most and the far ones only a little, but never to zero, or the field would end in a cliff. Every figure also has a cap on how far anything can rise or lean, and the view is fitted to the most extreme pose, so nothing leaves the frame.
Two easy bugs
The card that can’t decide. Point at a card and it rises. As it rises, its edge slides out from under the pointer, so it thinks you’ve left and drops. Then it’s under the pointer again, and it rises again. The flicker happens because the pointer is checked against where the card is drawn. Checking against where the card rests, which never moves, fixes it.
Drawings that never stop. A page that keeps redrawing its figures when nothing is moving keeps the computer busy and drains the battery. In hairline every figure shares one clock. Each spring reports when it’s done, and when all of them are, the clock stops. Figures scrolled out of view don’t count, and moving your pointer starts it again.
Try it
All six figures are free and open source at hairline.lucasmarkes.com. If you build with an AI coding agent, there’s also a skill that teaches it to draw new figures following these rules:
npx skills add lucasmarkes/hairlineIf you make something with it, I’d like to see it.