Icemoon ← All posts

Technical

What "human-like touch" actually means

August 1, 2026 · 8 min read

Every automation tool claims human-like input. Very few say what they mean by it. Here is the actual shape of the problem, and why a straight line is such a loud signal.

The default is a straight line

Ask almost any automation framework to swipe from A to B and you get linear interpolation: a fixed number of touch points spaced evenly along the segment between the two, delivered at a fixed interval, over a fixed duration. In code it is about four lines and it works perfectly.

It is also unlike anything a finger has ever done. Three things give it away, and none of them require sophisticated analysis to spot:

  1. The path is exactly straight. Human motion curves. The arm rotates around a joint; the thumb pivots. Perfectly straight is the anomaly.
  2. The velocity is constant. Real movements accelerate, cruise, decelerate. A constant-velocity gesture has a rectangular velocity profile, which no muscle produces.
  3. It repeats exactly. The same gesture twice with identical coordinates and identical timing is the strongest signal of the three. Humans have variance; machines have to be told to.
LINEAR INTERPOLATION CUBIC BÉZIER
The dashed path is what a default swipe traces. The solid path is one sample from a family of curves.

Curving the path

A cubic Bézier curve is the standard tool here, for the same reason it is standard in vector graphics: four points describe a smooth arc with intuitive control. Two of them are the endpoints you already have — where the finger lands and where it lifts. The other two are control points that bend the path between them.

B(t) = (1−t)³·P₀ + 3(1−t)²t·P₁ + 3(1−t)t²·P₂ + t³·P₃

  P₀  touch-down point
  P₁  first control point   ← randomised per gesture
  P₂  second control point  ← randomised per gesture
  P₃  lift point
  t   parameter from 0 to 1

Randomising P₁ and P₂ within sensible bounds gives you a different arc every time from the same start and end. That alone kills the "identical repeat" signal, which is the cheapest one to detect.

The bounds matter. Control points too close to the straight line produce a curve indistinguishable from linear; too far out and the finger appears to loop around the screen. The realistic envelope is a modest bow — a few percent of the total travel distance, perpendicular to the direction of motion, with the bow direction itself varying.

The velocity profile is the harder half

Here is the part that most implementations miss. Having a curved path is not enough if you sample it at uniform intervals of t, because uniform t on a Bézier gives you nearly uniform speed. You get a curved path traversed at robot pace.

Human reaching movements have been studied for decades, and they converge on a consistent shape. The classic result is the minimum-jerk model (Flash and Hogan, 1985): when people move a limb from one point to another, the trajectory they choose is very close to the one that minimises jerk — the rate of change of acceleration. The velocity profile that falls out of it is a smooth, symmetric, bell-shaped curve.

In practice that means: slow at the start, fastest around the midpoint, slowing into the target. So instead of stepping t linearly, you step it through an easing function whose derivative is bell-shaped, and sample the curve at those non-uniform positions.

A useful sanity check: plot the distance between consecutive touch points in your generated gesture. If they are all the same length, your velocity is constant no matter how curved the path looks.

Real profiles are not perfectly symmetric either — the deceleration phase tends to be slightly longer than the acceleration phase, especially for small targets, because the last part of the movement is a correction. Which leads directly to the next piece.

Fitts's law, and why duration should not be a constant

Fitts's law is one of the more durable results in human-computer interaction. It says movement time scales with the difficulty of the target:

MT = a + b · log₂(2D / W)

  MT  movement time
  D   distance to the target
  W   width of the target
  a,b empirically fitted constants

The practical reading: a long swipe takes longer than a short one, and hitting a small button takes longer than hitting a big one — and the relationship is logarithmic, not linear.

Most automation ignores this entirely and uses one duration for every gesture. That produces a distinctive artefact: short swipes that are implausibly slow and long swipes that are implausibly fast. Deriving duration from distance and target size — with noise on top — is a small change that removes a whole class of outliers.

Taps are not points

A tap looks simpler than a swipe and is often handled worse. The default behaviour of most tooling is to compute the centre of the target element and touch exactly that pixel, every time.

Humans do not. Tap positions on a target scatter in a roughly two-dimensional Gaussian around the centroid, with the spread growing as the target gets bigger — people are more careless with big buttons because they can afford to be. There is also a systematic bias: taps tend to land slightly below and toward the thumb's side of centre, because of how the contact patch of a finger maps to a reported point.

So a realistic tap samples a position from a distribution over the element's bounds rather than taking its centre, and varies contact duration too. Press durations are not constant either; they follow a long-tailed distribution, with most taps brief and an occasional long one where attention wandered.

The timing between actions

Everything above concerns single gestures. Zoom out one level and there is another distribution: the gaps between actions.

Automation defaults to fixed sleeps — sleep(2) between every step. The resulting inter-action histogram is a spike. Human inter-action gaps are long-tailed: mostly short, occasionally much longer when someone reads something, gets distracted, or switches apps. A log-normal-ish distribution is a far better approximation than a constant, and it costs nothing to implement.

The same logic applies at session scale, which is worth repeating because it is so often skipped: a schedule that fires at exactly the same minute every day and runs for exactly the same duration produces a pattern that is trivially visible in aggregate, no matter how good the individual swipes are.

Putting it together

PropertyNaive automationCloser to human
Swipe pathStraight segmentCubic Bézier, control points randomised per gesture
VelocityConstantBell-shaped, minimum-jerk-like, asymmetric deceleration
DurationFixed constantDerived from distance and target size, plus noise
Tap positionExact element centreSampled from a distribution over the element bounds
Press lengthFixedLong-tailed distribution
Gaps between actionssleep(2)Long-tailed, occasionally much longer
Session timingSame minute dailyJittered start and duration

None of this is exotic mathematics. It is a handful of well-known distributions applied at the right layer. What makes it rare is that it has to be built into the input layer from the start — you cannot bolt naturalistic motion onto a framework whose primitive is "move finger from A to B in N milliseconds".

That is the design decision behind Icemoon's input layer: every swipe is generated as its own curve with its own timing, rather than replayed from a template. It is one layer of several — as the companion post on detection argues, network identity and session rhythm usually carry more weight than gesture mechanics. But it is the layer that is cheapest for anyone to check and most commonly left at its defaults.

See the difference on your own device

Icemoon generates every gesture fresh — unique Bézier path, natural velocity profile, varied timing — on real iPhones driven from your Mac. No jailbreak, no code.

Start free trial
All posts Home vs Appium MCP server