Every ketamin.* function, the persistent sandbox and the on_tick runtime.
Overview
Everything in ketamin.* is callable from both the one-shot Lua editor and the persistent sandbox loaded through ketamin.persist(src). Drawing helpers and per-frame hooks only work inside ketamin.on_tick functions. All bindings dispatch on the overlay UI thread, one-shot per frame.
Persistent runtime
The persistent sandbox keeps lua_State alive across frames. Register per-frame work with on_tick and the runtime calls it every overlay tick.
| Function | Behavior |
|---|
ketamin.persist(src) | Loads a chunk into the persistent sandbox. Locals in the chunk survive between frames; the chunk only runs once. |
ketamin.on_tick(fn) | Registers fn(dt) for per-frame execution. Multiple registrations append. dt is seconds since the last tick, clamped to [0, 1]. |
ketamin.clear_ticks() | Removes every registered tick function. |
ketamin.dt() | Returns the last frame's delta in seconds. |
A tick function that errors is logged, compacted out of the sequence and the surviving handlers continue. Draw bindings outside a tick silently no-op.
Player and world
| Function | Returns |
|---|
ketamin.pos() | x, y, z for the local ped. |
ketamin.heading() | Local ped heading in degrees. |
ketamin.setheading(deg) | Writes heading via native. |
ketamin.tp(x, y, z) | One-shot SET_ENTITY_COORDS on the local ped. |
ketamin.entity_coord(ped) | x, y, z for any entity handle. |
ketamin.all_players() | Array of {handle, x, y, z, hp, name, is_self} from the live snapshot. |
ketamin.cam_coord() | Gameplay camera x, y, z. |
ketamin.cam_rot() | Gameplay camera pitch, roll, yaw. |
ketamin.world_to_screen(x, y, z) | Returns sx, sy, or nil if the point is offscreen or behind the camera. |
ketamin.screen_size() | Overlay viewport w, h. |
Feature toggles
Every flag the UI flips is also reachable from Lua. Flipping the Lua binding and ticking the UI checkbox call the same path through scripts::run_source.
| Function | Writes |
|---|
ketamin.esp(bool) | Master ESP enable. |
ketamin.esp_box / esp_health / esp_nametags / esp_tracers / esp_corners / esp_distance / esp_self / esp_skeleton(bool) | Individual ESP sub-flags. Any sub-flag on makes the overlay populate and draw. |
ketamin.noclip(bool) | UI-thread WASD warp via SET_ENTITY_COORDS. |
ketamin.freecam(bool) | Delegates to camera::set_active; mouse look stays on the game's own camera, WASD translates the ped. |
ketamin.aim(bool) | Master aim enable; silent / trigger / aim-assist sub-flags gate on this. |
ketamin.silentaim(bool) | Closest-target health zero on fire. |
ketamin.triggerbot(bool) | Press attack when GET_ENTITY_PLAYER_IS_FREE_AIMING_AT returns a ped. |
ketamin.aimassist(bool) | Nudge SET_GAMEPLAY_CAM_RELATIVE_PITCH / HEADING toward the closest target. |
ketamin.aimbot(bool) | Alias of aimassist. |
ketamin.aimfov(deg) / aimsmooth(float) / aimdist(m) | Aim policy sliders. |
ketamin.aimbone("head" | "neck" | "chest" | "pelvis") | Target bone selection. |
Player actions
Single-shot natives known safe on the UI thread. Each returns the game's boolean result.
| Function | Notes |
|---|
ketamin.god(bool) | SET_ENTITY_INVINCIBLE. |
ketamin.heal(hp, armor) | Writes health + armour on the local ped. |
ketamin.wanted(level) | SET_PLAYER_WANTED_LEVEL 0–5. |
ketamin.giveweapon("WEAPON_X", ammo) | Weapon name as the native model string. |
ketamin.ammo(hash, n) | SET_PED_AMMO with explicit weapon hash. |
ketamin.loadout("pistol" | "ar" | "sniper" | "all") | Preset weapon bundle. |
ketamin.superjump() | Per-tick-only flag; call from on_tick. |
ketamin.speed(mult) | Multiplies sprint / swim speed. |
ketamin.hud(bool) | Game HUD toggle. |
ketamin.fixcar() | Repair + wash the current vehicle. |
ketamin.ragdoll(ms) | Ragdoll for the given duration. |
ketamin.explode() | Explosion at the local ped. |
ketamin.suicide() | Health to zero. |
Teleport presets
| Function | Destination |
|---|
ketamin.tphome() | Michael's house. |
ketamin.tplsia() | Los Santos International. |
ketamin.tpmrpd() | Mission Row PD. |
ketamin.tpvinewood() | Vinewood Hills. |
ketamin.tpaltruist() | Altruist cult. |
ketamin.tptop() | Maze Bank roof. |
Vehicles
| Function | Notes |
|---|
ketamin.car(model) / ketamin.vspawn(model) | Unavailable on this build — RequestModel is thread-sensitive and no safe game-thread hop ships yet. Returns nil, reason. |
ketamin.deletecar() | Deletes the current or nearest vehicle. |
ketamin.flipcar() | Resets rotation to (0, 0, heading). |
ketamin.boost(mult) | Forward speed burst. |
ketamin.carinfo() | Table {handle, model_hash}. |
ketamin.fixcar() | See player actions. |
ketamin.cars | Lua array of 20 popular model names (adder, zentorno, t20, osiris, kuruma, insurgent, hydra, lazer, savage, deluxo, oppressor, ...). |
World
| Function | Behavior |
|---|
ketamin.time(h, m, s) | NETWORK_OVERRIDE_CLOCK_TIME. |
ketamin.weather(name) | Accepts CLEAR, RAIN, THUNDER, SNOW, CLEARING, FOGGY, EXTRASUNNY, SMOG, OVERCAST, BLIZZARD, NEUTRAL, XMAS. |
ketamin.pause(bool) | SET_GAME_PAUSED. |
Drawing (only inside on_tick)
All drawing bindings write to ImGui::GetBackgroundDrawList(). They detect a thread-local in_tick flag set by lua_tick; outside a tick they silently no-op so a misplaced call never corrupts the UI frame.
| Function | Signature |
|---|
ketamin.draw_box | (x, y, w, h, r, g, b, a [, thickness]) |
ketamin.draw_filled_box | (x, y, w, h, r, g, b, a [, rounding]) |
ketamin.draw_text | (x, y, text, r, g, b, a [, size]) |
ketamin.draw_line | (x1, y1, x2, y2, r, g, b, a [, thickness]) |
ketamin.draw_circle | (x, y, radius, r, g, b, a [, thickness]) |
| Function | Returns |
|---|
ketamin.is_key_down(vk) | (GetAsyncKeyState(vk) & 0x8000) != 0. |
ketamin.mouse_pos() | Screen-space mouse x, y. |
Native dispatch
For natives we don't ship a named binding for, call them directly.
| Function | Behavior |
|---|
ketamin.native(hash, args...) | Hash as integer or "0x..." string; args coerced from number / boolean / string. Returns the first uint64 result or nil on failure. |
ketamin.fx_status() | Returns (status_text, ready_bool) for the dispatcher. |
Natives that touch streaming or network VM state (RequestModel, CreateVehicle, Delete*, SetEntityCoordsNoOffset, DRAW_LINE and other render primitives) are blacklisted in fx_native::is_thread_sensitive and refuse off-thread dispatch.
Utility
| Function | Behavior |
|---|
ketamin.notify(text) | In-game feed post. |
ketamin.alert(text) | Feed ticker alert. |
ketamin.print_console(text) | Appends to the local editor output. |
ketamin.gettime() | GetTickCount64() in milliseconds. |
Configs
Persist UI state to %LOCALAPPDATA%\KetaminStudio\configs\<name>.json. The hand-rolled JSON covers all g_s ESP and aim fields; missing keys keep their defaults.
| Function | Behavior |
|---|
ketamin.config_save(name, payload) | Writes payload text as <name>.json. |
ketamin.config_load(name) | Reads the file; returns "" if missing. |
ketamin.config_list() | Array of saved config names (no extension). |
ketamin.config_delete(name) | Removes the file. |
ketamin.g_s_json() | Flat JSON snapshot of the current settings struct. |
ketamin.g_s_apply(json) | Restores values from a snapshot. |
Hotkey automation
| Function | Behavior |
|---|
ketamin.hotkey(vk, "lua src") | Background VK poll; runs src through the one-shot sandbox on key edge. Re-binding overwrites the previous entry. Pass nil as the source to cancel. |
Example: pure-Lua ESP
ketamin.persist([[
ketamin.on_tick(function(dt)
for _, p in ipairs(ketamin.all_players()) do
if not p.is_self then
local sx, sy = ketamin.world_to_screen(p.x, p.y, p.z)
if sx then
ketamin.draw_box(sx - 20, sy - 40, 40, 80, 255, 60, 60, 220)
ketamin.draw_text(sx - 18, sy - 55, p.name or "ped", 255, 255, 255, 240)
end
end
end
end)
]])
Example: pure-Lua freecam
ketamin.persist([[
local active = false
local last_toggle = 0
ketamin.on_tick(function(dt)
local now = ketamin.gettime()
if ketamin.is_key_down(0x73) and now - last_toggle > 250 then
active = not active; last_toggle = now
ketamin.notify(active and "freecam on" or "freecam off")
end
if not active then return end
local x, y, z = ketamin.pos()
local s = ketamin.is_key_down(0x10) and 1.6 or 0.4 -- Shift = boost
if ketamin.is_key_down(0x57) then y = y + s end -- W
if ketamin.is_key_down(0x53) then y = y - s end -- S
if ketamin.is_key_down(0x41) then x = x - s end -- A
if ketamin.is_key_down(0x44) then x = x + s end -- D
if ketamin.is_key_down(0x20) then z = z + s end -- Space
if ketamin.is_key_down(0x11) then z = z - s end -- Ctrl
ketamin.tp(x, y, z)
end)
]])
Thread + safety
- Everything dispatches on the overlay UI thread, one native call-set per frame.
- Do not sleep or block in
on_tick; the overlay runs at your FPS cap. - A tick function that throws a Lua error is removed from the sequence after the frame; others keep running.
- Drawing outside
on_tick silently no-ops — the background draw list is only valid inside the UI frame.