Algorithm Explained
This page provides an in-depth explanation of the WindMouse algorithm, its physics principles, and the mathematics behind human-like mouse movement generation.
Overview
The WindMouse algorithm generates realistic, non-linear mouse trajectories by simulating physical forces acting on the cursor. Unlike simple linear interpolation (which moves in a straight line at constant speed), WindMouse creates curved paths with variable speed—closely mimicking how humans naturally move a mouse.
The Problem with Traditional Mouse Movement
Most automation tools use linear interpolation:
# Naive linear movement (easily detectable)
for t in range(steps):
x = start_x + (dest_x - start_x) * (t / steps)
y = start_y + (dest_y - start_y) * (t / steps)
move_mouse(x, y)
This approach has several problems:
Perfect straight lines: Humans rarely move the mouse in perfectly straight lines
Constant speed: Real human movement accelerates and decelerates
No variation: Repeated movements follow identical paths
Easily detectable: Bot detection systems can identify these patterns
The WindMouse Solution
WindMouse solves these problems by simulating a physics-based system with three key forces:
Gravity: Attracts the cursor toward the target (directed force)
Wind: Adds randomness and curvature to the path (random force)
Velocity Damping: Slows down as the cursor approaches the target
The algorithm operates in discrete time steps, updating velocity and position at each iteration.
Mathematical Model
Physics Simulation
At each time step, the algorithm updates the cursor state based on forces:
Position Update:
Velocity Update:
Where: - \(v_x, v_y\) are velocity components - \(W_x, W_y\) are wind force components - \(G_x, G_y\) are gravity force components
Gravity Force
Gravity provides the directed force pulling the cursor toward the target:
Where:
- \(g\) is gravity_magnitude (default: 9)
- \(dist = \\sqrt{(dest_x - x)^2 + (dest_y - y)^2}\) is the distance to target
This creates a force vector pointing directly at the target with magnitude proportional to gravity_magnitude.
Wind Force
Wind adds randomness and curvature. Its behavior changes based on distance from target:
Far from target (\(dist \\geq damped\\_distance\)):
Close to target (\(dist < damped\\_distance\)):
Where: - \(r\) is a random value in [0, 1] - \(w = \\min(wind\\_magnitude, dist)\) is the effective wind magnitude - \(\\sqrt{3} \\approx 1.732\) is the damping factor - \(\\sqrt{5} \\approx 2.236\) is the fluctuation factor
The wind force: - Decays over time (divided by √3 each step) - Adds random fluctuations when far from target - Only decays (no new randomness) when close to target
Velocity Clamping
The velocity magnitude is clamped to prevent excessive speed:
If \(|v| > max\\_step\):
Where \(r\) is random in [0, 1].
This ensures the cursor doesn’t move too fast while adding slight speed variation.
Algorithm Pseudocode
Here’s the complete algorithm in pseudocode:
function WindMouse(start_x, start_y, dest_x, dest_y, gravity, wind, max_step, damped_dist):
x, y = start_x, start_y
vx, vy = 0, 0
wx, wy = 0, 0
while distance(x, y, dest_x, dest_y) >= 1:
dist = distance(x, y, dest_x, dest_y)
wind_current = min(wind, dist)
# Update wind
if dist >= damped_dist:
wx = wx/sqrt(3) + (2*random() - 1) * wind_current/sqrt(5)
wy = wy/sqrt(3) + (2*random() - 1) * wind_current/sqrt(5)
else:
wx = wx/sqrt(3)
wy = wy/sqrt(3)
if max_step < 3:
max_step = random() * 3 + 3
else:
max_step = max_step/sqrt(5)
# Update velocity with wind and gravity
vx = vx + wx + gravity * (dest_x - x) / dist
vy = vy + wy + gravity * (dest_y - y) / dist
# Clamp velocity
v_mag = sqrt(vx^2 + vy^2)
if v_mag > max_step:
v_clip = max_step/2 + random() * max_step/2
vx = (vx / v_mag) * v_clip
vy = (vy / v_mag) * v_clip
# Update position
x = x + vx
y = y + vy
yield (round(x), round(y))
Parameter Effects
Understanding how each parameter affects the generated path:
gravity_magnitude
Effect: Controls the strength of attraction to the target.
- Low (3-6): Weak attraction
Path wanders more
Takes longer to reach target
More influenced by wind
Very curved trajectories
- Medium (7-10): Balanced (Default: 9)
Natural-looking curves
Reasonable convergence time
Good balance of control and randomness
- High (11-15): Strong attraction
More direct paths
Faster convergence
Less curve, more purposeful
Dominates wind effect
Visual Effect:
Low gravity (5): Medium gravity (9): High gravity (13):
*-----> *----> *--->
/ \\ / \\ | \\
/ \\ / \\ | \\
o T o T o T
(very curved) (natural) (fairly direct)
wind_magnitude
Effect: Controls the amount of random curvature and unpredictability.
- Low (0-2): Minimal wind
Nearly straight paths
Predictable movement
Less human-like
Good for speed-priority scenarios
- Medium (3-5): Moderate wind (Default: 3)
Natural curves
Good human-like appearance
Balanced unpredictability
- High (6-10): Strong wind
Very curved paths
Highly unpredictable
May look drunk/erratic
Good for testing detection systems
Visual Effect:
Low wind (1): Medium wind (3): High wind (8):
*--> *~> *~~>
| \\ / \\ / |\\
| \\ / \\ / | \\
o T o T o | T
(nearly straight) (gentle curve) (chaotic path)
max_step
Effect: Controls the maximum speed (pixels per step).
- Low (5-10): Slow movement
Takes longer to reach target
More controlled, deliberate
Good for precision tasks
- Medium (12-18): Normal speed (Default: 15)
Balanced speed and control
Natural-looking pace
- High (20-30): Fast movement
Quick traversal
May look less natural at very high values
Good for efficiency-priority scenarios
Note: The actual movement speed also depends on tick_delay and step_duration in move_to_target().
damped_distance
Effect: Distance from target (in pixels) where behavior changes.
- Low (5-10): Late damping
Maintains speed and wind longer
Sharper approach to target
Less cautious
- Medium (12-15): Balanced (Default: 12)
Natural slowdown
Smooth approach
Human-like deceleration
- High (20-30): Early damping
Slows down far from target
Very cautious approach
May look hesitant
Visual Effect:
Low damped_dist (8): Medium (12): High (25):
*=======> *=====> *==>
||||||||| ||||--> ||---->
-----o-------T -----o-------T -----o-------T
(fast until close) (gradual slow) (early slowdown)
Why These Specific Constants?
You might wonder why the algorithm uses \(\\sqrt{3}\) and \(\\sqrt{5}\):
- √3 ≈ 1.732 (Wind Damping)
Provides gradual decay of wind force
Balances persistence and decay
Empirically found to produce natural-looking curves
Fast enough to converge, slow enough to maintain influence
- √5 ≈ 2.236 (Wind Fluctuation & Velocity Reduction)
Scales random fluctuations appropriately
Prevents wind from overwhelming gravity
Creates smooth randomness rather than jitter
Also used for max_step reduction near target
These constants were likely chosen through experimentation to balance: - Convergence speed - Path naturalness - Computational stability - Aesthetic appeal
Algorithm Characteristics
Convergence Guarantee
The algorithm is guaranteed to converge to the target because:
Gravity always points toward target and doesn’t decay
Wind decays over time (divided by √3 each step)
As distance decreases, wind becomes less effective
Close to target, only gravity remains (no new wind)
The stopping condition is distance < 1 pixel, which is always eventually satisfied.
Non-Determinism
The algorithm is non-deterministic due to random wind fluctuations. Running it multiple times with the same parameters produces different paths.
This is a feature, not a bug: - Prevents pattern recognition - Mimics human inconsistency - Makes bot detection harder
Scale Independence
The algorithm works well across different screen resolutions and distances because:
Parameters are pixel-based (scale-agnostic)
Wind magnitude adapts to distance (
min(wind_magnitude, dist))Gravity is normalized by distance (
/ dist)
However, you may want to tune parameters for very large distances (e.g., 4K displays) or very short distances (small UI elements).
Comparison to Other Algorithms
Linear Interpolation
# Linear
x = start_x + (dest_x - start_x) * t
WindMouse advantages: - ✅ Non-linear paths - ✅ Variable speed - ✅ Unpredictable - ❌ More computationally expensive
Bézier Curves
Bézier curves can create smooth paths but:
❌ Require predetermined control points
❌ Path is deterministic given control points
❌ No physical simulation
❌ Speed is uniform (unless manually varied)
WindMouse advantages: - ✅ Physics-based (more natural) - ✅ Emergent behavior - ✅ No need to specify control points
Simplex/Perlin Noise
Noise functions can add randomness but:
❌ Don’t inherently move toward target
❌ Require combining with directed movement
❌ May produce unnatural patterns
WindMouse advantages: - ✅ Built-in target seeking - ✅ Balanced randomness and purpose - ✅ Complete solution in one algorithm
Implementation Details
Generator-Based Architecture
The wind_mouse() function is a generator, yielding coordinates one at a time:
def wind_mouse(...) -> Generator[tuple[Coordinate, Coordinate], None, None]:
# ...
yield Coordinate(move_x), Coordinate(move_y)
Benefits:
Memory efficient (doesn’t store entire path)
Allows real-time movement
Can be interrupted mid-path
Enables custom tick-based control
Coordinate Type Safety
WindMouse uses NewType for coordinates:
Coordinate = NewType("Coordinate", int)
This provides type safety without runtime overhead, helping catch errors at type-check time.
Optimization Opportunities
For performance-critical applications, consider:
Pre-compute sqrt(3) and sqrt(5): Already done in the library
Use NumPy vectorization: Already used for
np.hypot()Reduce tick_delay: Set to 0 for maximum speed
Reduce step_duration: Use smaller values (0.01-0.05)
Increase max_step: Higher values = fewer total steps
Example optimized configuration:
from windmouse.pyautogui_controller import PyautoguiMouseController
from windmouse import Coordinate
mouse = PyautoguiMouseController(
max_step=20, # Increase speed
gravity_magnitude=12, # More direct
)
mouse.dest_position = (Coordinate(800), Coordinate(600))
mouse.move_to_target(
tick_delay=0, # No delay
step_duration=0.01 # Fast transitions
)
Visualizing the Algorithm
To better understand the algorithm, you can visualize the path:
import matplotlib.pyplot as plt
from windmouse.core import wind_mouse, Coordinate
# Generate path
path = list(wind_mouse(
Coordinate(0), Coordinate(0),
Coordinate(500), Coordinate(500),
gravity_magnitude=9,
wind_magnitude=3,
max_step=15,
damped_distance=12
))
# Extract x and y coordinates
xs, ys = zip(*path)
# Plot
plt.figure(figsize=(10, 10))
plt.plot(xs, ys, 'b-', linewidth=1, alpha=0.7)
plt.plot(xs[0], ys[0], 'go', markersize=10, label='Start')
plt.plot(xs[-1], ys[-1], 'ro', markersize=10, label='End')
plt.legend()
plt.grid(True, alpha=0.3)
plt.axis('equal')
plt.title('WindMouse Path Visualization')
plt.show()
Further Reading
For more information on human-computer interaction and mouse movement patterns:
Fitts’s Law - Model of human movement
Motor Control Research - Neuroscience of movement
Bot Detection Techniques - How automation is detected
Related Algorithms:
Inverse Kinematics (robotics)
Path smoothing algorithms
Particle systems in computer graphics
Next Steps
Now that you understand the algorithm, explore:
The complete API Reference reference
Practical examples in Usage Guide
Experiment with parameters to find optimal settings for your use case