How I Think Through an Interaction
Every interaction I create, I run through a rough set of steps that keep my head clear about what I'm actually trying to build and achieve. There is no one size that fits all here, so this is less a checklist and more a loose flow I tend to follow. In practice there is almost always a lot of back and forth between these steps, but if I had to jot the rough shape of it down, it would look like this.
Understanding Interaction: Input vs Output
The first thing I care about is what I actually want to happen. Not the tools, not the code, just the plain fact of it: I do something, and the screen answers. Once I can picture that, I split it into two halves. There is an input, and there is an output.
From there I treat the whole thing as one simple relationship. A to B. Input A, output B, and nothing else on my mind yet.
What is the input? A drag, a tap, a double tap, a point on a timeline? I don't lock the exact mechanism down yet. That comes later. For now I just fix that there is an input, and sit with it for a second.
Then I look at the other end. What do I actually want to move on screen? The card shrinks. The opacity falls. Something slides along a curve. One clear thing I can point at.
Cutting it down like this is what turns the noise in my head into something I can hold. As the input changes, the output changes. That is the whole sentence, and everything after it is just filling in the blanks.
The last thing I do is refuse to leave it vague. I pin both ends to a range. Not "the card shrinks" but how much, and between what and what. As the finger drags down from 0 to 300pt, the card scales from 1.0 to 0.5. Now it isn't a feeling anymore. It's a line I can draw, and soon enough, a number I can tune.
Taking It Apart
Once I know the input and the output, I still don't jump into designs or code. I sit with the interaction a little longer and try to really understand what I want out of it.
So I take it apart. Most interactions that feel good are not one thing, they are a few smaller ones braided together, and I try to name each one. Take a card that follows a curve as you drag. Look closer and it isn't only following the curve, it also shrinks as it travels along it. The follow and the shrink are two separate behaviors, but they have to run off the same input, or the whole thing falls out of sync. That harmony is the point, and it only shows up once I have pulled the pieces apart.
The deeper I look, the more niche it gets. Small sub-behaviors keep surfacing the longer I stay with it.
While I do this, I sketch. Fast and rough, whatever gets it out of my head and onto paper. I'm not drawing to make it pretty, I'm drawing so I can actually see the thing instead of holding a cluttered mess in my mind. A few of mine are below.
And this is where it clicks. Once it's on paper, the patterns show themselves: the same value quietly driving two or three different things at once. That is usually the interaction, sitting right there.
Toolbox for Creating
I mostly build for Apple's platforms, so I mostly live in Apple's tools. Underneath almost everything is SwiftUI or UIKit. That layer is the scaffold: it holds the views, owns the gestures, and passes values around to the call sites that actually do the animating.
Past that, I think of the tools as tiers, because no single method fits every interaction. There are three I reach for: SwiftUI and UIKit, Core Animation, and Metal shaders.
The thing that ties them together is worth saying out loud. On Apple platforms, rendering is one layered system that bottoms out at the GPU. Whatever you write ends up as a tree of layers that the render server composites on the GPU. Each tier just lets you describe that same work at a different level of detail.
Which tier I pick comes straight back to the dissection from the last step. If it is plain position, scale, rotation, or opacity, SwiftUI handles most of it with almost no effort. If it is heavier and needs to run in step with the display, like real physics or a spring engine ticking every frame, I move to Core Animation. And if I need genuinely fine-grained, pixel-level control, I drop down to a Metal shader.
On the design side I work mostly in Figma. When something is simple enough that it doesn't really need me, I hand it to paper.design to lay out on my artboard, then go back and adjust the parts that want a human eye.
Testing the Interaction
This is the part I find most important, and it is the one I overlooked for the longest time.
The values I pick, or the ones the AI suggests, almost never feel right on the first try. A drag threshold is a little too eager, a spring settles a beat too slow. The slow way to fix that is to go back to Xcode, change the number, rebuild, run, and see. Then do it all again for the next tweak. That loop quietly kills the feel before you ever find it.
So I stopped doing that. Now every interaction I build ships with a small settings sheet, and every value I care about lives in there as a slider or a text field I can move while the app is running. If the drag threshold feels off, I pull up the sheet, nudge it, and I'm testing the new value in the same second, with no rebuild at all.
It sounds like a small thing. When I first started building interactions I didn't even know to do it, and the day I started, everything got faster and simpler. That is exactly why I wanted to share it.