Blog / aim-engine · · 11 min read · Signed KyTech Research

Aim Assist Internals: What Makes a Modern Aim Engine Look Human

FSM states, cone hysteresis, iterative intercept, ballistics, and the humanization chain that keeps a modern aim engine off the Overwatch pile.

Snap-to-head is a solved problem from 2004. Any junior with a memory reader and atan2f can build one in an afternoon. The reason those aim engines get banned inside a week is that they read as bots to every behavioral heuristic shipping in modern anti-cheats: perfectly linear trajectories, zero settle noise, sub-frame acquisition, identical bone offsets across a magazine. A serious aim engine in 2026 spends less code on "where is the head" and more on "how would a good human get there."

This post walks the architecture of that second part. It is not an operational guide, and no code below is copy-paste-runnable. The pseudocode exists to show the shape of the state machine and the math, because the shape is what separates a modern aim engine from a 20-year-old triggerbot. If you are picking between products rather than architectures, our 2026 buyer's guide is the better starting point.

The state machine is the whole thing

Every serious aim engine we have shipped at KyTech is a finite state machine first, math library second. The math determines where the crosshair goes; the FSM decides whether the crosshair is allowed to move at all, and how aggressively. Four states cover everything worth covering:

IDLE          no target in cone, no work to do
ACQUIRING     candidate in cone, reaction timer running
TRACKING      locked on target, applying corrections
RELEASING     target lost or exited cone, decaying alpha to zero

Transitions are what matter. IDLE -> ACQUIRING fires when a target enters the acquisition cone and passes a visibility test. ACQUIRING -> TRACKING fires only after the reaction delay expires, which is where humanization begins. TRACKING -> RELEASING fires when the target exits the exit cone, dies, or LOS breaks. RELEASING -> IDLE fires when the alpha envelope hits zero, typically 80 to 140 ms after release begins.

enum class AimState { Idle, Acquiring, Tracking, Releasing };

struct AimContext {
    AimState  state;
    Target*   target;          // may be null in Idle/Releasing
    uint64_t  state_entered_ns;
    float     reaction_ms;     // sampled once on Idle->Acquiring
    float     alpha_envelope;  // 0..1, drives smoothing weight
    Vec3      bone_offset;     // sampled per-engagement, not per-tick
};

void AimTick(AimContext& ctx, const World& w, float dt) {
    switch (ctx.state) {
        case AimState::Idle:
            if (Target* t = PickCandidate(w, EnterConeFov())) {
                ctx.target         = t;
                ctx.reaction_ms    = SampleReactionMs(140.0f, 35.0f);
                ctx.bone_offset    = SampleBoneOffset(t);
                ctx.state_entered_ns = NowNs();
                ctx.state          = AimState::Acquiring;
            }
            break;

        case AimState::Acquiring:
            if (ReactionElapsed(ctx)) ctx.state = AimState::Tracking;
            if (!TargetStillValid(ctx, w)) ctx.state = AimState::Releasing;
            break;

        case AimState::Tracking:
            if (!InExitCone(ctx.target, w) || !TargetStillValid(ctx, w))
                ctx.state = AimState::Releasing;
            else
                ApplyTrackingCorrection(ctx, w, dt);
            break;

        case AimState::Releasing:
            ctx.alpha_envelope = DecayAlpha(ctx.alpha_envelope, dt);
            if (ctx.alpha_envelope < 1e-3f) {
                ctx.target = nullptr;
                ctx.state  = AimState::Idle;
            }
            break;
    }
}

The single most common mistake in amateur cheats is treating every tick like a new engagement. Sampling the bone offset once per IDLE -> ACQUIRING transition (and holding it through RELEASING) is what makes bullets group during a burst. Sample it per tick and every round hits a slightly different point on the target's silhouette, which reads as inhuman precision spread over a burst rather than a human's tight cluster on their intended point of aim.

Cone hysteresis: why enter and exit thresholds differ

A single FOV threshold produces the "snap flicker" bug that has outed countless cheats on Overwatch review. Target crosses the FOV boundary, cheat engages, cheat pulls slightly, target now barely outside FOV, cheat disengages, human overshoots because assist vanished. On a slow-motion review this is unmistakable.

The fix is hysteresis: two cones with different radii.

Parameter Typical value Purpose
Enter FOV 1.5 degrees at 1x sens Reject targets outside intended engagement
Exit FOV 3.0 degrees at 1x sens Prevent flicker at the boundary
Visibility gate traced ray + fuzzed sample Reject occluded targets without perfect wall-check tell
Reaction floor 90 ms Minimum plausible human reaction
Reaction mean 140 ms Log-normal center for burst-fire humans

Enter at 1.5 degrees, exit at 3.0. Once locked, the engine tolerates twice the deviation before releasing. Combined with the RELEASING alpha decay, transitions look like a human who acquired a target, tracked it briefly past their crosshair, then let go. No frame-perfect snap on entry, no frame-perfect release on the edge.

Distance bands and per-band alpha floors

A single smoothing coefficient across all ranges is another beginner tell. Close targets need sharp lock; a submachine-gun engagement at 200 units in Apex Legends S25 (the 2026 spring update) resolves in under 200 ms. Far targets need steady, low-pass tracking; a Kraber at 3800 units resolves in about a second and needs almost none of the crosshair velocity a close engagement demands.

We use three bands with independent alpha floors and prediction weights:

  • Close: 0 to 500 units. Alpha floor 0.55, feed-forward 0.15, prediction disabled.
  • Mid: 500 to 3000 units. Alpha floor 0.30, feed-forward 0.40, prediction enabled.
  • Far: 3000+ units. Alpha floor 0.18, feed-forward 0.55, prediction enabled with heavier bullet-time term.

The floor matters because the alpha envelope from the FSM multiplies against these values. During ACQUIRING, alpha is ramping from 0 toward 1 across the reaction window; the band floor is what the effective alpha reaches at full engagement. A close engagement wants aggressive correction; a far engagement wants low-frequency tracking because the target's angular velocity is small and any high-frequency correction will overshoot and read as jitter.

Prediction: the iterative intercept solver

Aim prediction is intercept, not extrapolation. Extrapolation asks "where will the target be at time T?" Intercept asks "at what time T will a bullet fired now hit the target?" The two answers differ because T itself depends on where the target will be. This is a fixed-point problem.

struct Intercept { Vec3 aim_point; float t_hit; };

Intercept SolveIntercept(Vec3 shooter, Vec3 target_pos, Vec3 target_vel,
                         float muzzle_v, float gravity_scale)
{
    Vec3  p = target_pos;
    float t = 0.0f;
    for (int i = 0; i < 3; ++i) {
        Vec3  predicted = target_pos + target_vel * t;
        float dist      = Length(predicted - shooter);
        float t_new     = dist / muzzle_v;
        if (fabsf(t_new - t) < 1e-4f) { t = t_new; p = predicted; break; }
        t = t_new;
        p = predicted;
    }
    // Ballistic drop compensation applied after intercept resolves.
    p.z += 0.5f * kGravity * gravity_scale * t * t;
    return { p, t };
}

Three iterations with an early-out at 0.1 ms delta covers every realistic engagement inside 400 meters. Four is wasteful; two is visibly wrong on strafing targets past 2000 units. The bullet drop compensation is applied after the intercept resolves because drop depends on time of flight, and time of flight was what we were solving for.

Ballistic solver: closed-form low-arc pitch

For weapons with meaningful drop (bows, snipers, launchers), the pitch angle to hit a target at horizontal distance x and vertical delta y with muzzle velocity v under gravity g has a closed-form low-arc solution:

pitch = atan2( v^2 - sqrt(v^4 - g*(g*x^2 + 2*y*v^2)), g*x )

If the discriminant v^4 - g*(g*x^2 + 2*y*v^2) is negative, the target is out of range. Every weapon carries a gravity_scale because engines apply per-weapon multipliers (Apex's Bocek and Sentinel both fly under scaled gravity, and CS2 build 10000+ still uses per-weapon bulletgravity scalars). Hardcoding one gravity value is a giveaway on Overwatch review because the arc is subtly wrong on half the weapons in the game.

Humanization: the three signals that get people banned

Beam mode gets you banned. Not because Easy Anti-Cheat or Vanguard detects the code, but because Overwatch jurors on any game with peer review will flag a clip of your crosshair traveling on a perfectly linear path at constant angular velocity. Machine-learning behavioral pipelines on the anti-cheat side (Byfron's post-Roblox-acquisition-2022 pipeline; Vanguard's server-side telemetry since the TPM 2.0 mandate for League in 2024) score exactly this kind of motion.

Three signals, applied additively to the tracked angle before it is written back to view state:

Reaction delay

Human reaction to a target appearing in the periphery follows a log-normal distribution, not a Gaussian. Fast humans cluster around 120 ms; slow ones tail out to 280 ms. Sampling from LogNormal(mean=140ms, sigma=35ms) on IDLE -> ACQUIRING and refusing to enter TRACKING until that timer expires gives you a distribution of engagement latencies that matches human data collected from Aim Lab and Kovaak public leaderboards.

Settle drift and breathing

A human at rest holding a mouse still is not still. There is a low-frequency oscillation from breathing (0.8 to 1.8 Hz) and a small amplitude wobble from micro-muscle drift. We inject a summed sinusoid at 0.06 degrees amplitude modulated by a slow noise term (a 1D Perlin noise walk keeps the drift smooth without periodic artifacts):

float BreathingOffsetDeg(uint64_t now_ns, float amp_deg, float hz_lo, float hz_hi) {
    float t   = now_ns * 1e-9f;
    float hz  = hz_lo + (hz_hi - hz_lo) * PerlinNoise1(t * 0.13f);
    float phi = sinf(2.0f * kPi * hz * t);
    // Add a tiny high-frequency micro-drift.
    float micro = 0.15f * amp_deg * PerlinNoise1(t * 3.7f);
    return amp_deg * phi + micro;
}

Fire-steadying

Humans grip the mouse harder when firing. Wobble decreases while the trigger is held. Multiply the breathing offset by 0.20 while LMB is down, then ease back to 1.0 over 180 ms after release. On a review clip this produces exactly the pattern good players show: relaxed sway between engagements, tight hold during a burst, sway returning after.

Feed-forward on moving targets

The correction term in ApplyTrackingCorrection blends two signals: proportional (angle error toward the aim point) and derivative (rate of change of the desired angle). The derivative is the feed-forward term, weighted at 40 percent for mid-band engagements against moving targets. Without it, the crosshair lags a strafing target by the smoothing time constant; with it, the crosshair leads at roughly the target's angular velocity and the proportional term collapses to correction noise.

The trick is that feed-forward is only useful on movers. Standing targets contribute zero derivative, so the term costs nothing when it is not needed. Strafing targets get led correctly, which looks like a human tracking a strafe rather than a bot playing whack-a-mole with the target's current position.

Why "just crank alpha to 1.0" is a career-ender

Behavioral anti-cheat does not need root access to your machine to flag you. It needs your view angle stream, at a sample rate the server already collects. Server-side view-angle telemetry has been standard since Valve's CS2 rollout (build 10000 series in early 2025), and mandatory since the LoL Vanguard integration in 2024. The pipeline is:

  1. Sample view angle deltas at server tick rate.
  2. Compute angular velocity, angular acceleration, and jerk (third derivative).
  3. Fit distributions per player, compare to per-weapon and per-rank baselines.
  4. Flag outliers for human review.

Beam mode flunks step 3 catastrophically. Alpha-1 tracking produces near-zero jerk and near-constant angular velocity during engagements, which no human on any hardware produces. The humanized signal chain above intentionally injects the jerk profile of a human hand, at cost of about 2 to 3 percent aim accuracy versus beam mode. Two percent accuracy is the price of not being banned, and that is a trade every serious KyTech customer is happy to make.

Tuning knobs and their effects

The knobs that matter, and what each one actually does when you turn it:

Knob Low value effect High value effect
Enter FOV Fewer false engagements, more missed acquisitions Sticks to anything in view, obvious on review
Exit FOV Frequent snap-flicker Drags crosshair off intended target after kill
Reaction mean Sub-human reaction time (bannable) Missed opportunities on quick peeks
Alpha floor (close) Sluggish close lock, feels bad Snap lock, reads as bot on kill-cam
Alpha floor (far) Steady scope hold, natural Jitter on scoped targets, obvious tell
Feed-forward weight Lag on movers Overshoot on direction changes
Bone offset variance Tight groups (good) Bullets spray across silhouette (bot tell)
Breathing amplitude Beam mode look Wobbly crosshair, misses at range

How KyTech handles this

KyTech was founded in 2025 by two engineers and has shipped a kernel-mode driver as its base substrate from day one. Our aim architecture for KyTech Apex implements the FSM, cone hysteresis, banded prediction, closed-form ballistic solver, and humanization chain described above. Each of our supported titles (Apex, CS2, Overwatch 2, Black Ops 7, Forza Horizon 6, Roblox) carries its own tuning profile, because the kill-cam review surface and the behavioral telemetry pipeline differ between engines and between publishers.

KyTech Apex specifically ships the HWID spoofer beta at time of writing, which sits underneath the aim engine and handles the identity side of the risk model. The aim engine handles the behavioral side. Both matter, and both are the reason we spend engineering time on things like log-normal reaction sampling and per-engagement bone offset rather than shipping the sub-500-line "snap to head" that made up most of the market in 2018. If you are evaluating options, the 2026 cheat buyer's guide covers where our stack fits against the field and which trade-offs matter for which anti-cheat.

We do not publish detection numbers, uptime percentages, or user counts, and we suggest treating any provider that does with suspicion. The math and the state machine above are what a serious aim engine looks like under the hood. Everything else is marketing. See the full product lineup for current availability.

Signed by KyTech Research

We still play these games and we still push every build in production. If something in here is wrong, and eventually something will be, ping us in Discord and we will fix it.

Enough theory. get in.

The loader is one click away. Ring-0 kernel driver, polymorphic per download, memory-only injection. Six games across VAC, EAC, Ricochet, Byfron, and Warden.

Get in ›