05-03-26

Smooth Analog Movement Script

This Lua script for Rebind hardware input converts discrete WASD key presses into smooth analog-style movement, providing a more natural and gamepad-like feel. Configure smoothing duration for desired

rebindlua scriptanalog movementwasdsmoothinghardware inputscript

Question

Movement keys to analog-style smoothing

Rebind AI

Movement Keys to Analog-Style Smoothing

This script converts discrete WASD key presses into smooth analog-style movement, useful for games that support analog input or for creating gamepad-like feel from keyboard controls.

luau
-- rebind: min_sdk=0.1.0
-- rebind: name=Movement Smoothing
-- rebind: description=Convert WASD to smooth analog movement

local cfg = UI.Schema({
    enabled = UI.Toggle(true, { label = "Enable" }),
    smoothing = UI.Slider(100, { min = 10, max = 200, suffix = "ms", label = "Smoothing Duration" }),
    keys = UI.Text("WASD", { label = "Movement Keys", maxLength = 10 }),
})

local movements = {
    W = { x = 0, y = -1 },
    A = { x = -1, y = 0 },
    S = { x = 0, y = 1 },
    D = { x = 1, y = 0 },
}

local activeKeys = {}
local movementTask = nil

local function updateMovement()
    if movementTask and movementTask:IsRunning() then
        movementTask:Cancel()
    end

    movementTask = Run(function()
        local startTime = System.Time()
        local duration = cfg.smoothing

        while true do
            local elapsed = System.Time() - startTime
            local progress = math.min(elapsed / duration, 1.0)

            local totalX = 0
            local totalY = 0

            for key, _ in pairs(activeKeys) do
                if movements[key] then
                    totalX = totalX + movements[key].x
                    totalY = totalY + movements[key].y
                end
            end

            if totalX == 0 and totalY == 0 then
                break
            end

            local easeProgress = progress * progress * (3 - 2 * progress)

            HID.Move(totalX * easeProgress, totalY * easeProgress)
            Sleep(16)

            if progress >= 1.0 then
                startTime = System.Time()
            end
        end
    end)
end

function OnDown(key)
    if not cfg.enabled or not movements[key] then
        return true
    end

    activeKeys[key] = true
    updateMovement()
    return false
end

function OnUp(key)
    if not cfg.enabled or not movements[key] then
        return true
    end

    activeKeys[key] = nil
    updateMovement()
    return false
end

function OnStop()
    if movementTask and movementTask:IsRunning() then
        movementTask:Cancel()
    end
end

function OnBlur()
    activeKeys = {}
    if movementTask and movementTask:IsRunning() then
        movementTask:Cancel()
    end
end

How It Works

Smooth Acceleration:

  • Tracks which movement keys are currently held
  • Continuously interpolates from current position to target position over the configured duration
  • Uses an ease-in-out curve (smoothstep) for natural acceleration/deceleration

Multi-Directional Support:

  • Combines active key vectors (e.g., pressing W+D creates diagonal movement)
  • Cancels opposing directions (A+D = stationary)
  • Updates smoothly when keys are pressed or released

Performance:

  • Runs in a coroutine to avoid blocking input processing
  • 16ms per frame (~60fps smooth movement)
  • Only active when keys are held

Configuration:

  • smoothing: Duration in milliseconds for acceleration/deceleration (100ms = responsive, 200ms = floaty)
  • enabled: Toggle on/off without reloading

Learn more