marketplace/gaming

Path of Exile Helper

QoL shortcuts, inventory automation, and grid calibration for Path of Exile.

@rebindv0.1.0free

Other ways to install
$rebind install @rebind/poe-helper

Gallery

Path of Exile Helper preview

Readme

Path of Exile Utilities

A collection of quality-of-life automation shortcuts for Path of Exile, featuring fast inventory management, safe chat macros, combat helpers, and a guided 4-step grid calibration wizard that adapts to any screen resolution or UI scale.


Features

  • Guided Calibration (F10): Calibrate your inventory and trade windows in seconds without guessing pixel coordinates. Persisted locally to coords.json.
  • Fast Stash Transfer (Ctrl + Left Click): Hold Ctrl and Left Click to continuously transfer items until released.
  • Full Inventory Dump (Left Arrow): Automatically Ctrl + Click every slot across all 60 inventory cells.
  • Trade Window Inspector (Up Arrow): Sweeps your cursor over all 60 trade window cells to reveal item stats.
  • Instant Portal Scroll (Grave / ~): Opens inventory (B), right-clicks your bottom-right portal scroll slot, closes inventory, and restores your cursor position.
  • Chat Shortcuts: One-tap hotkeys for /hideout, /leave, /destroy, and quick whispered replies (ty).
  • Combat Loop Helper (Right Click): Optional toggleable loop that cycles right-click attacks with secondary abilities (Q and E).
  • Modifier Remap: Maps Left Windows to Right Shift to avoid accidental taskbar interruptions.

First-Time Calibration

Before using the inventory dumping, right-clicking, or trade inspection features, calibrate your grid coordinates for your display resolution:

  1. In Path of Exile, open your character inventory (B).
  2. Press F10 (or your configured calibration key). An in-game notification will appear for Step 1/4.
  3. Hover your cursor over the center of the top-left inventory slot (row 1, col 1) and press F10.
  4. Hover your cursor over the center of the bottom-right inventory slot (row 5, col 12) and press F10.
  5. Open a trade window with an NPC or player. Hover your cursor over the center of the top-left trade slot and press F10.
  6. Hover your cursor over the center of the bottom-right trade slot and press F10.

A success notification will appear. Grid positions are calculated via linear interpolation and saved to coords.json next to your script. You only need to repeat this if you change game resolution or UI scaling.


Default Controls

Every keybind can be customized in the script's Options tab.

Inventory & Management

ActionDefault KeyDescription
Calibrate GridF10Starts / advances the 4-step setup wizard
Rapid TransferCtrl + Mouse1 (Hold)Rapidly left-clicks while Ctrl is held
Dump InventoryLeft ArrowIterates all 60 slots with Ctrl + Click
Right-Click AllRight ArrowIterates all 60 slots with Right Click
Inspect TradeUp ArrowHovers every item in the trade window
Instant Portal` (Grave)Triggers portal scroll in slot (12, 5)

Chat Shortcuts

ActionDefault KeyCommand Sent
HideoutF1/hideout
Quick 'ty'F2Ctrl + Enter -> ty -> Enter
Leave PartyF3/leave
Destroy ItemF11/destroy

Diagnostics

ActionKeyDescription
Cursor PositionF12Logs current screen X, Y to notifications and console

Configuration

In the Rebind Options tab for this script, you can:

  • Toggle the Right-Click Combat Loop (enable_right_click).
  • Reassign any hotkey or chat command trigger.

Reviews

No reviews yet. Be the first, from the app.

Source

Version 0.1.0 (current)

main.luau

--[[
  rebind: min_sdk=3.0.0
]]

local cfg = UI.Schema({
  enable_right_click  = UI.Toggle(false, { label = "Enable Right-Click Combat Loop" }),
  setup_key           = UI.Keybind("F10", { label = "Calibrate Coordinates" }),
  portal_key          = UI.Keybind("Grave", { label = "Instant Portal", group = "Hotkeys" }),
  dump_key            = UI.Keybind("Left", { label = "Dump Inventory (Ctrl+Click)", group = "Hotkeys" }),
  right_click_all_key = UI.Keybind("Right", { label = "Right-Click All Slots", group = "Hotkeys" }),
  inspect_trade_key   = UI.Keybind("Up", { label = "Inspect Trade Window", group = "Hotkeys" }),
  hideout_key         = UI.Keybind("F1", { label = "Go to Hideout", group = "Chat Commands" }),
  ty_key              = UI.Keybind("F2", { label = "Quick Reply 'ty'", group = "Chat Commands" }),
  leave_key           = UI.Keybind("F3", { label = "Leave Party", group = "Chat Commands" }),
  destroy_key         = UI.Keybind("F11", { label = "Destroy Held Item", group = "Chat Commands" }),
})

local COORDS_FILE = "coords.json"

local function load_coords()
  if File.Exists(COORDS_FILE) then
    local ok, data = pcall(File.ReadJSON, COORDS_FILE)
    if ok and data then return data end
  end
  return {
    inv_tl   = { x = 1780, y = 818 },
    inv_br   = { x = 2495, y = 1078 },
    trade_tl = { x = 494,  y = 324 },
    trade_br = { x = 1209, y = 584 },
  }
end

local function save_coords(data)
  File.WriteJSON(COORDS_FILE, data)
end

local coords = load_coords()
local setup_step = 0

local function get_inv_cell(col, row)
  local dx = (coords.inv_br.x - coords.inv_tl.x) / 11
  local dy = (coords.inv_br.y - coords.inv_tl.y) / 4
  return {
    x = math.floor(coords.inv_tl.x + col * dx),
    y = math.floor(coords.inv_tl.y + row * dy),
  }
end

local function get_trade_cell(col, row)
  local dx = (coords.trade_br.x - coords.trade_tl.x) / 11
  local dy = (coords.trade_br.y - coords.trade_tl.y) / 4
  return {
    x = math.floor(coords.trade_tl.x + col * dx),
    y = math.floor(coords.trade_tl.y + row * dy),
  }
end

local function send_chat(command)
  HID.Press("Enter", 15)
  Sleep(25)
  HID.Type(command)
  Sleep(25)
  HID.Press("Enter", 15)
end

-- Calibration hotkey
Bind(cfg.setup_key, function()
  local pos = Input.GetMousePos()

  if setup_step == 0 then
    setup_step = 1
    UI.Notify("Step 1/4: Hover TOP-LEFT inventory slot center, press key", "info")
  elseif setup_step == 1 then
    coords.inv_tl = { x = pos.x, y = pos.y }
    setup_step = 2
    UI.Notify(string.format("Saved TL (%d, %d). Step 2/4: Hover BOTTOM-RIGHT inventory slot, press key", pos.x, pos.y), "info")
  elseif setup_step == 2 then
    coords.inv_br = { x = pos.x, y = pos.y }
    setup_step = 3
    UI.Notify(string.format("Saved BR (%d, %d). Step 3/4: Open trade, hover TOP-LEFT trade slot, press key", pos.x, pos.y), "info")
  elseif setup_step == 3 then
    coords.trade_tl = { x = pos.x, y = pos.y }
    setup_step = 4
    UI.Notify(string.format("Saved Trade TL (%d, %d). Step 4/4: Hover BOTTOM-RIGHT trade slot, press key", pos.x, pos.y), "info")
  elseif setup_step == 4 then
    coords.trade_br = { x = pos.x, y = pos.y }
    save_coords(coords)
    setup_step = 0
    UI.Notify(string.format("Calibration saved to %s", COORDS_FILE), "success")
    Log.Info(string.format("Saved grid coordinates to %s", COORDS_FILE))
  end
end)

-- Key remapping
Bind.Remap("LWin", "RShift")

-- Rapid Ctrl + Left Click (stash transfer loop)
Bind("Mouse1", {
  when = function()
    return Input.GetModifiers().ctrl
  end,
  action = Async(function()
    while Input.IsDown("Mouse1") and Input.GetModifiers().ctrl do
      HID.Press("Mouse1", 10)
      Sleep(15)
    end
  end),
})

-- Rapid Right Click combat sequence (Q + E skills)
Bind("Mouse2", {
  when = function()
    return cfg.enable_right_click
  end,
  action = Async(function()
    while Input.IsDown("Mouse2") and cfg.enable_right_click do
      HID.Press("Mouse2", 15)
      Sleep(50)
      if not Input.IsDown("Mouse2") then break end
      Sleep(10)
      HID.Press("Q", 15)
      if not Input.IsDown("Mouse2") then break end
      Sleep(10)
      HID.Press("E", 15)
      Sleep(10)
    end
  end),
})

-- Instant Portal: open inventory, right click bottom-right scroll slot, close inventory
Bind(cfg.portal_key, Async(function()
  local orig_pos = Input.GetMousePos()
  local portal_cell = get_inv_cell(11, 4)

  HID.Press("B", 15)
  Sleep(15)
  HID.MoveTo(portal_cell.x, portal_cell.y)
  Sleep(10)
  HID.Press("Mouse2", 15)
  Sleep(15)
  HID.Press("B", 15)
  Sleep(10)
  HID.MoveTo(orig_pos.x, orig_pos.y)
end))

-- Dump inventory (Ctrl + Click)
Bind(cfg.dump_key, Async(function()
  HID.Down("LCtrl")
  for row = 0, 4 do
    for col = 0, 11 do
      local pos = get_inv_cell(col, row)
      HID.MoveTo(pos.x, pos.y)
      Sleep(10)
      HID.Press("Mouse1", 10)
      Sleep(10)
    end
  end
  HID.Up("LCtrl")
end))

-- Right click all slots
Bind(cfg.right_click_all_key, Async(function()
  if not cfg.enable_right_click then
    HID.Press("Mouse2", 15)
    return
  end
  for row = 0, 4 do
    for col = 0, 11 do
      local pos = get_inv_cell(col, row)
      HID.MoveTo(pos.x, pos.y)
      Sleep(10)
      HID.Press("Mouse2", 10)
      Sleep(10)
    end
  end
end))

-- Inspect items in trade window
Bind(cfg.inspect_trade_key, Async(function()
  for row = 0, 4 do
    for col = 0, 11 do
      local pos = get_trade_cell(col, row)
      HID.MoveTo(pos.x, pos.y)
      Sleep(10)
    end
  end
end))

-- Chat shortcuts
Bind(cfg.hideout_key, Async(function()
  send_chat("/hideout")
end))

Bind(cfg.ty_key, Async(function()
  HID.Combo("LCtrl+Enter")
  Sleep(25)
  HID.Type("ty")
  Sleep(25)
  HID.Press("Enter", 15)
end))

Bind(cfg.leave_key, Async(function()
  send_chat("/leave")
end))

Bind(cfg.destroy_key, Async(function()
  send_chat("/destroy")
end))

-- Cursor position debugger
Bind("F12", function()
  local pos = Input.GetMousePos()
  UI.Notify(string.format("Cursor: %d, %d", pos.x, pos.y), "info")
  Log.Info(string.format("Cursor: %d, %d", pos.x, pos.y))
end)

function OnStop()
  HID.Up("LCtrl")
  HID.Up("Mouse1")
  HID.Up("Mouse2")
end

function OnBlur()
  HID.Up("LCtrl")
  HID.Up("Mouse1")
  HID.Up("Mouse2")
end