gurp logo gurp docs

Lua Reference · api_version 3

gurp Lua API Reference

Everything a gurp Lua script can use: the gurp API, the Roblox-style compatibility layer, the sandbox rules, and worked examples.

Overview

start

gurp runs Lua 5.4 scripts in a sandbox. Scripts can read and write game memory, walk the Roblox instance tree, draw on screen, build small windows, and feed extra players to gurp's ESP and aimbot.

Running scripts

  • Open the Lua tab in the menu, create or load a script and press run.
  • Output from print, warn and gurp.log goes to the Lua console.
  • Resetting the Lua environment stops every running script: any gurp.wait/gurp.sleep_ms raises "Lua environment reset" and the script ends.
  • Up to 8 scripts can run at the same time.

What's in the box

  • gurp: timing, input, files, HTTP, offsets, logging
  • gurp.memory: raw reads and writes
  • gurp.sdk: instance helpers (names, children, positions, CFrames, attributes, Value objects)
  • gurp.cache: add your own players to gurp's player list
  • gurp.ui: simple windows with buttons, checkboxes, sliders and colour pickers
  • gurp.draw: lines, circles, rectangles and text over the game
  • A Roblox-style layer: Color3, Vector2, game:GetService, Drawing.new, task, readfile/writefile and more, so UI libraries written for other executors (like SevereLib) run as-is.
Objects are passed around as raw memory addresses (integers), not Roblox instances. See Values & Types.

Your First Script

startexample

Print your position every second

local function root_part()
  local lp = gurp.get_localplayer()
  if lp == 0 then return nil end
  local character = gurp.sdk.character(lp)
  if not character or character == 0 then return nil end
  local hrp = gurp.sdk.find_child(character, "HumanoidRootPart")
  if not hrp or hrp == 0 then return nil end
  return hrp
end

while true do
  local hrp = root_part()
  if hrp then
    local p = gurp.sdk.position(hrp)
    print(("you are at %.1f, %.1f, %.1f"):format(p.x, p.y, p.z))
  end
  gurp.wait(1)
end

Draw a label above your head

local function valid(x) return x and x ~= 0 end

while true do
  gurp.draw.clear()                      -- start this frame's drawing from scratch
  local character = gurp.sdk.character(gurp.get_localplayer())
  local head = valid(character) and gurp.sdk.find_child(character, "Head")
  if valid(head) then
    local p = gurp.sdk.position(head)
    local s = gurp.draw.world_to_screen(p.x, p.y + 2, p.z)
    if s then
      gurp.draw.text(s.x, s.y, "me", 0.6, 0.9, 0.4, 1, true, 16)
    end
  end
  gurp.wait(0)                           -- shows the frame, lets gurp breathe
end
Long-running scripts must call gurp.wait (or gurp.sleep_ms, or yield inside a RunService callback). Drawings only appear when the script waits, and a script that never waits hits the instruction limit.

Sandbox & Limits

rules

Available standard libraries

  • base functions, coroutine, table, string, math, utf8
  • os with only the safe parts (os.clock, os.time, os.date, os.difftime)
  • loadstring(src) / load(src): compile Lua source, returns the function or nil, error. Precompiled bytecode is refused.

Removed

  • io, debug, package, require, dofile, loadfile
  • os.exit, os.execute, os.remove, os.rename, os.tmpname, os.getenv, os.setlocale
  • For files use gurp's file functions; they're limited to a sandbox folder.

Limits

LimitValue
Scripts running at once8
Memory per script32 MB
Instructions between waitsabout 50 million (each gurp.wait/gurp.sleep_ms resets the count); going over raises "script instruction limit"
Script / loadstring source size1 MB
Strings passed into gurp functions8192 characters (longer ones are cut)
One gurp.log/print line2048 characters
Draw commands per script8192 per frame
gurp.ui windows / elements24 windows, 200 elements per window
gurp.http_get response2 MB
gurp.sdk.childrenfirst 256 children
Errors inside gurp functions never crash the game: bad addresses just return nil or false. Your own Lua errors stop the script and print to the console.

Values & Types

rules

Shapes used across the API

NameWhat it is
addr / objAn integer memory address. Instances (parts, players, the camera...) are passed as their address. 0 means "none".
vec3{ x = number, y = number, z = number }
matrix3Rows of a 3×3 rotation: { {r00, r01, r02}, {r10, r11, r12}, {r20, r21, r22} }
cframe{ r00 .. r22 = rotation, x, y, z = position } (flat table, 12 numbers)
colour argumentsSeparate r, g, b, a numbers from 0 to 1; leaving them all out means white.
nil vs 0: lookups like sdk.find_child, sdk.character and get_localplayer return 0 when nothing is found, and nil only when the object you passed in was invalid. Check both: if x and x ~= 0 then.
Addresses go stale. A character's parts are freed when it respawns, and everything changes when you switch servers. Look objects up again instead of keeping them for long.

gurp

core

Game objects

FunctionReturnsNotes
get_base_address()addrRobloxPlayerBeta base; 0 when not attached
get_datamodel()addrThe DataModel (game); 0 if none
get_workspace()addr0 if none
get_camera()addrCurrent camera; 0 if none
get_localplayer()addrYour Player; 0 if none
get_offset(namespace, name)integer|nilCurrent offset, e.g. get_offset("Humanoid", "Health"). nil only if the name is unknown (an offset can legitimately be 0). See the Offsets list.

Timing

FunctionReturnsNotes
wait(seconds=0)nothingPauses the script (0–60 s). Shows your queued drawings and keeps the UI responsive. Raises "Lua environment reset" if the environment is reset.
sleep_ms(ms=0)nothingSame as wait but in milliseconds (0–60000).
time_ms()integerMilliseconds since Windows started; use for timers.

Input & screen

FunctionReturnsNotes
is_key_down(vk)boolWindows virtual-key code, e.g. 0x01 left mouse, 0x02 right mouse, 0x45 E, 0x20 Space. Works whether or not Roblox is focused.
key_tap(key, hold_ms=50)boolPresses and releases a key in Roblox (focuses Roblox first). key is a key code, a digit (1 or "1" for the number row), a Enum.KeyCode entry, or its name ("E"). Waits hold_ms (0–5000) between press and release.
key_down(key) / key_up(key)boolPresses or releases a key and leaves it that way. Same key forms as key_tap.
mouse_click(button="left", hold_ms=20)boolClicks a mouse button at the current cursor position. button is "left", "right", "middle" or 1–3. Waits hold_ms (0–5000) between press and release.
mouse_down(button="left") / mouse_up(button="left")boolPresses or releases a mouse button and leaves it that way.
mouse_pos()x, yCursor position on the desktop (same space as gurp.draw).
screen_size()width, heightSize of the main monitor.

Misc

FunctionReturnsNotes
log(message)nothingPrints [Lua] message to the console. print also works (no prefix).
clamp(value, min, max)numberSame as math.clamp.
set_desync(enabled)trueForces gurp's desync on while true, even if it's off in the menu. Pass false to hand control back.

Example: hold a key

local VK_E = 0x45
while true do
  if gurp.is_key_down(VK_E) then
    gurp.log("E is held at " .. gurp.time_ms())
  end
  gurp.wait(0.1)
end

Files & HTTP

coreio

All file paths are relative to %APPDATA%\gurproblox\ui-configs\. Paths with .., drive letters, or more than 240 characters are refused. Both / and \ work.

Files

FunctionReturnsNotes
fs_write(path, data)boolCreates folders as needed and overwrites the file. Max 1 MB.
fs_read(path)string|nilnil if missing.
fs_exists(path)booltrue only for files.
fs_isdir(path)bool
fs_mkdir(path)boolCreates nested folders.
fs_delete(path)trueDeletes a file or an empty folder. Always returns true.
fs_list(path){string}Up to 256 files and folders, each as a full path from the sandbox root (fs_list("myscript/configs") gives "myscript/configs/a.json"), so results can go straight into fs_read.

HTTP

FunctionReturnsNotes
http_get(url)stringGET only, http:// or https://. Returns the body whatever the status code. Raises an error on bad URLs, connection failures, or bodies over 2 MB, so wrap it in pcall. Time-outs: 5 s to connect, 15 s to receive.

Example: save settings as JSON

local Http = game:GetService("HttpService")   -- from the Roblox-style layer
local path = "myscript/settings.json"

local settings = { fov = 90, enabled = true }
if gurp.fs_exists(path) then
  settings = Http:JSONDecode(gurp.fs_read(path)) or settings
end
settings.fov = settings.fov + 1
gurp.fs_write(path, Http:JSONEncode(settings))

local ok, body = pcall(gurp.http_get, "https://example.com/version.txt")
if ok then print("latest version: " .. body) else warn(body) end

Fields & gurp.game

core

gurp fields

FieldValue
gurp.api_version3. Check it with gurp.api_version >= 3 if you share scripts.
gurp.has_cache_apitrue when gurp.cache exists.
gurp.is_debugtrue only in developer builds. Those builds also have debug_read_file, debug_write_file, debug_other_offsets_path and debug_other_offsets_paths, which aren't available to normal users.

gurp.game

FieldValue
is_in_gamebool
base_addressaddr
datamodeladdr
workspaceaddr
cameraaddr
localplayeraddr
gurp.game is filled in once, when the script starts, and never updates. After a server hop or respawn, use the gurp.get_* functions instead.

gurp.memory

module

FunctionReturnsNotes
read_u64(addr)integer|nil8 bytes; use for pointers.
read_u32(addr)integer|nil4 bytes, unsigned.
read_f32(addr)number|nil32-bit float.
read_bool(addr)bool|nil1 byte.
write_u64(addr, value)bool
write_u32(addr, value)bool
write_f32(addr, value)bool
write_bool(addr, value)boolLua truthiness.
Reads return nil and writes return false for invalid addresses. A plain write can be undone by the game on the next frame. For moving parts, prefer gurp.sdk.set_rotation, which holds its write briefly.

Example: read your health with an offset

local lp = gurp.get_localplayer()
local character = gurp.sdk.character(lp)
local humanoid = character and character ~= 0 and gurp.sdk.find_child_of_class(character, "Humanoid") or 0
local health_off = gurp.get_offset("Humanoid", "Health")
if humanoid ~= 0 and health_off then
  local hp = gurp.memory.read_f32(humanoid + health_off)
  print("health: " .. tostring(hp))
end
Never hard-code offsets like 0x194: they change with every Roblox update. gurp.get_offset always gives the current value.

gurp.sdk

moduleinstances

Every function takes the instance's address as its first argument. With an invalid address, getters return nil and setters return false.

Identity & hierarchy

FunctionReturnsNotes
name(obj)stringInstance Name.
display_name(player)stringA Player's DisplayName.
class_name(obj)stringe.g. "Part", "Humanoid".
children(obj){addr}First 256 children; empty table for invalid objects.
find_child(obj, name)addrFirst child with that name; 0 if none.
find_child_of_class(obj, class)addrFirst child whose class is exactly class (no inheritance: "BasePart" won't match a Part); 0 if none.
character(player)addrThe player's character model; 0 while dead or loading.
players_service()addr|nilThe Players service. Its children are the players.

Parts & physics

FunctionReturnsNotes
position(part)vec3World position.
velocity(part)vec3Studs per second.
size(part)vec3
cframe(part)cframeRotation + position (see types).
rotation(part)matrix3
set_rotation(part, matrix3)boolWrites the rotation and keeps re-applying it for 300 ms so physics doesn't undo it.
anchored(part)bool
set_anchored(part, on)bool
set_can_collide(part, on)bool
primitive(part)addrThe part's internal physics object.
primitive_flags(part)integerBit flags; bit values from get_offset("PrimitiveFlags", "Anchored"), "CanCollide", "CanTouch", "CanQuery".

Camera

FunctionReturnsNotes
camera_position(camera)vec3Pass gurp.get_camera().
camera_rotation(camera)matrix3
set_camera_rotation(camera, matrix3)bool
field_of_view(camera)numberDegrees.
set_field_of_view(camera, fov=70)bool

Humanoids & GUI objects

FunctionReturnsNotes
humanoid_state(humanoid)integerRoblox HumanoidStateType number, e.g. 3 Jumping, 5 Freefall, 8 Running, 13 Seated, 15 Dead.
text(gui)stringText of a TextLabel/TextButton/TextBox.
background_color3(gui)vec3BackgroundColor3, with x, y, z = red, green, blue (0–1).

Value objects (IntValue, BoolValue, ObjectValue...)

FunctionReturnsNotes
value_u64(obj) / set_value_u64(obj, v)integer / boolIntValue (64-bit) and ObjectValue (an address).
value_u32(obj) / set_value_u32(obj, v)integer / boolLow 32 bits.
value_f32(obj) / set_value_f32(obj, v)number / bool32-bit float. NumberValue stores a 64-bit double, so it won't read correctly with this.
value_bool(obj) / set_value_bool(obj, v)bool / boolBoolValue.

Example: list everyone in the server

local players = gurp.sdk.players_service()
for _, plr in ipairs(gurp.sdk.children(players or 0)) do
  if gurp.sdk.class_name(plr) == "Player" then
    print(gurp.sdk.name(plr) .. " (" .. gurp.sdk.display_name(plr) .. ")")
  end
end

gurp.sdk attributes

moduleattributes

Reading

FunctionReturnsNotes
attribute_f32(obj, name, fallback=0)numberNumeric attribute; fallback if missing. Never nil.
attribute_bool(obj, name, fallback=false)boolBoolean attribute; fallback if missing.
attribute_dump(obj, max=32){entry}Up to max (1–256) attributes as { name, entry, value_ptr }.
attribute_values(obj, max=64){entry}Up to max (1–512) attributes as { name, entry, value_ptr, f32, f64, u32, bool }, the raw value read four ways. Pick the one that matches the attribute's type.
attribute_find(obj, query, contains=true, max=256){ name, entry, value_ptr }|nilFirst attribute whose name matches. contains=true matches part of the name; pass false for an exact match.
attribute_entry(obj, name)addr|nilAddress of the attribute's entry (exact name).
attribute_value_ptr(obj, name)addr|nilAddress of the attribute's value (exact name); read it with gurp.memory.
attribute_instance(obj)addrThe object's attribute storage; 0 if it has none.
attribute_probe(obj)stringA text report of what gurp found in the attribute storage. Handy when reads come back wrong.

Writing

FunctionReturnsNotes
attribute_set_f32(obj, query, value, contains=true, max=256)boolWrites a number, as a double or float to match how it's stored.
attribute_set_bool(obj, query, value, contains=true, max=256)boolWrites a byte, then reads it back; falls back to a numeric 0/1.
attribute_set_u32(obj, query, value, contains=true, max=256)boolWrites as a number first, then as a raw 32-bit integer.
The setters match part of the name by default (contains=true). Pass false as the 4th argument for exact matching, or you may write to the wrong attribute (e.g. "Ammo" also matches "MaxAmmo"). See the Attribute Cookbook.

gurp.cache

moduleplayers

Adds your own entries to gurp's player list. ESP, aimbot and the other player features then treat them like normal players. Use it for games where players aren't regular Roblox players (custom character systems, NPC bosses, etc.).

FunctionReturnsNotes
add_player(address, userid, name, display_name, team=0, health=100, max_health=100)boolAdds or updates an entry. address and userid together identify it; at least one must be non-zero. team is a Team instance address or 0.
set_player_part(userid, address, part_name, part)boolGives the entry a body part, e.g. "Head", "HumanoidRootPart", "UpperTorso". ESP boxes and aimbot use these.
set_player_humanoid(userid, address, humanoid)bool
set_player_health(userid, address, health, max_health)bool
remove_player(userid, address)bool
clear_players()trueRemoves every custom entry.
players_count()integerNumber of custom entries.

Example: feed NPCs from a folder

local folder = gurp.sdk.find_child(gurp.get_workspace(), "NPCs")
while true do
  for i, model in ipairs(gurp.sdk.children(folder)) do
    local id = 1000000 + i                     -- any stable id you choose
    gurp.cache.add_player(model, id, gurp.sdk.name(model), "", 0)
    for _, part in ipairs({ "Head", "HumanoidRootPart" }) do
      gurp.cache.set_player_part(id, model, part, gurp.sdk.find_child(model, part))
    end
  end
  gurp.wait(1)
end
Always pass the same userid + address pair for an entry. Mixing them up creates duplicates.

gurp.ui

moduleui

Small windows built from IDs. Call the element functions every loop: the first call creates the element, later calls update its label and return its current value. Values are kept per window_id + element_id.

Windows

FunctionReturnsNotes
window(id, title, x=100, y=100, w=300, h=180)boolCreates or updates a window. Width 80–1920, height 60–1080. Position and size are applied on the first call; after that only if the window isn't draggable. Windows are draggable by default, so the user's moves stick.
set_draggable(id, on) / get_draggable(id)boolget_draggable is true for windows that don't exist yet.
set_visible(id, on)boolHide or show without losing state.
clear_elements(id)boolRemoves the window's elements (their values are kept).
remove_window(id)boolRemoves the window and its saved values.
clear()trueRemoves every window and value.
set_interactive(on) / get_interactive()boolOn by default: Lua windows take mouse input whenever the cursor is over them, menu open or not. set_interactive(false) makes every Lua window display-only, so clicks pass through to the game (good for HUD-style windows). clear() and environment resets turn it back on.

Elements

FunctionReturnsNotes
text(win, id, text)boolPlain text line.
button(win, id, label)booltrue once per click.
checkbox(win, id, label, default=false)boolCurrent state.
slider_float(win, id, label, min=0, max=1, default=min, step=0)numberCurrent value. With step > 0 it snaps to multiples of step from min.
color(win, id, label, r=1, g=1, b=1)r, g, bColour picker; returns the current colour as three numbers 0–1.
separator(win, id)boolHorizontal line.
layout(win, same_line=false, width=0)boolApplies to the next element created: put it on the same line as the previous one, and/or give it width as a fraction of the window (0–1, 0 = default).

Reading and setting values

FunctionReturnsNotes
get_bool(win, id) / set_bool(win, id, v)boolCheckbox values.
get_float(win, id) / set_float(win, id, v)number / boolSlider values.

Example

gurp.ui.window("main", "My Script", 120, 120, 320, 200)
while true do
  local enabled = gurp.ui.checkbox("main", "enabled", "Enabled", true)
  local fov = gurp.ui.slider_float("main", "fov", "Field of view", 70, 120, 90, 1)
  gurp.ui.layout("main", false, 0.5)
  local r, g, b = gurp.ui.color("main", "tint", "Tint", 0.6, 0.9, 0.4)
  if gurp.ui.button("main", "reset", "Reset FOV") then
    gurp.ui.set_float("main", "fov", 90)
  end
  if enabled then
    gurp.sdk.set_field_of_view(gurp.get_camera(), fov)
  end
  gurp.wait(0)
end

gurp.draw

modulerender

How drawing works: each call adds a command to your script's list. The list is shown on screen when your script calls gurp.wait/gurp.sleep_ms, and stays up until you show a new one. Call gurp.draw.clear() at the start of every frame, or commands pile up (8192 max) and old ones stay on screen.
FunctionNotes
clear()Empties your command list.
text(x, y, text, r, g, b, a, centered=false, size=0)centered centres it horizontally on x. size 0 uses the menu font size (max 128). Returns false for empty text.
line(x1, y1, x2, y2, thickness=1, r, g, b, a)Thickness 0.5–32.
circle(x, y, radius=2, thickness=1, segments=0, r, g, b, a)Outline. segments 0 picks automatically (max 64).
circle_filled(x, y, radius=2, segments=0, r, g, b, a)
rect(x, y, w, h, r, g, b, a, rounding=0, filled=true, thickness=1)w, h are the size, not the bottom-right corner. Pass filled=false for an outline.
world_to_screen(x, y, z)Returns {x, y} in the same desktop coordinates the draw functions use, or nil if the point is behind the camera.
Colours are 0–1 (1, 0.5, 0, 1 = opaque orange). Leaving out all four colour arguments gives white. Draw functions return true (text returns false for empty text).
Filled rectangles at least 12×10 pixels that aren't nearly transparent block mouse clicks from reaching the game. That's what lets drawn menus (like SevereLib's) be clicked.

Example: crosshair that follows the mouse

while true do
  gurp.draw.clear()
  local mx, my = gurp.mouse_pos()
  gurp.draw.circle(mx, my, 10, 1.5, 32, 0.6, 0.9, 0.4, 1)
  gurp.draw.line(mx - 15, my, mx + 15, my, 1, 1, 1, 1, 0.8)
  gurp.draw.line(mx, my - 15, mx, my + 15, 1, 1, 1, 1, 0.8)
  gurp.draw.rect(mx + 14, my + 14, 60, 18, 0, 0, 0, 0.6, 4)
  gurp.draw.text(mx + 44, my + 15, "aim", 1, 1, 1, 1, true, 13)
  gurp.wait(0)
end

Offsets list

data

Every name gurp.get_offset(namespace, name) knows. Values are updated automatically after Roblox updates, so always look them up at run time.

NamespaceNames
AirPropertiesAirDensity, GlobalWind
AnimationTrackAnimation, Animator, IsPlaying, Looped, Speed, TimePosition
AnimatorActiveAnimations
AtmosphereColor, Decay, Density, Glare, Haze, Offset
AttachmentPosition
BasePartCastShadow, Color3, Locked, Massless, Primitive, Reflectance, Shape, Transparency
BeamAttachment0, Attachment1, Brightness, CurveSize0, CurveSize1, LightEmission, LightInfluence, Texture, TextureLength, TextureSpeed, Width0, Width1, ZOffset
BloomEffectEnabled, Intensity, Size, Threshold
BlurEffectEnabled, Size
ByteCodePointer, Size
CameraCameraSubject, CameraType, FieldOfView, ImagePlaneDepth, Position, Rotation, Viewport, ViewportSize
CharacterMeshBaseTextureId, BodyPart, MeshId, OverlayTextureId
ClickDetectorMaxActivationDistance, MouseIcon
ClothingColor3, Template
ColorCorrectionEffectBrightness, Contrast, Enabled, TintColor
ColorGradingEffectEnabled, TonemapperPreset
DataModelCreatorId, GameId, GameLoaded, JobId, PlaceId, PlaceVersion, PrimitiveCount, ScriptContext, ServerIP, ToRenderView1, ToRenderView2, ToRenderView3, Workspace
DepthOfFieldEffectEnabled, FarIntensity, FocusDistance, InFocusRadius, NearIntensity
DragDetectorActivatedCursorIcon, CursorIcon, MaxActivationDistance, MaxDragAngle, MaxDragTranslation, MaxForce, MaxTorque, MinDragAngle, MinDragTranslation, ReferenceInstance, Responsiveness
FakeDataModelPointer, RealDataModel
GuiBase2DAbsolutePosition, AbsoluteRotation, AbsoluteSize
GuiObjectBackgroundColor3, BackgroundTransparency, BorderColor3, Image, LayoutOrder, Position, RichText, Rotation, ScreenGui_Enabled, Size, Text, TextColor3, Visible, ZIndex
HumanoidAutoJumpEnabled, AutoRotate, AutomaticScalingEnabled, BreakJointsOnDeath, CameraOffset, DisplayDistanceType, DisplayName, EvaluateStateMachine, FloorMaterial, Health, HealthDisplayDistance, HealthDisplayType, HipHeight, HumanoidRootPart, HumanoidState, HumanoidStateID, IsWalking, Jump, JumpHeight, JumpPower, MaxHealth, MaxSlopeAngle, MoveDirection, MoveToPart, MoveToPoint, NameDisplayDistance, NameOcclusion, PlatformStand, PlatformStatePointer, RequiresNeck, RigType, SeatPart, Sit, TargetPoint, UseJumpPower, WalkTimer, Walkspeed, WalkspeedCheck
InstanceAttributeContainer, AttributeList, AttributeToNext, AttributeToValue, ChildrenEnd, ChildrenStart, ClassBase, ClassDescriptor, ClassName, Name, NameContainer, Parent, This
LightingAmbient, Brightness, ClockTime, ColorShift_Bottom, ColorShift_Top, EnvironmentDiffuseScale, EnvironmentSpecularScale, ExposureCompensation, FogColor, FogEnd, FogStart, GeographicLatitude, GlobalShadows, GradientBottom, GradientTop, LightColor, LightDirection, MoonPosition, OutdoorAmbient, Sky, Source, SunPosition
LocalScriptByteCode, GUID, Hash
MaterialColorsAsphalt, Basalt, Brick, Cobblestone, Concrete, CrackedLava, Glacier, Grass, Ground, Ice, LeafyGrass, Limestone, Mud, Pavement, Rock, Salt, Sand, Sandstone, Slate, Snow, WoodPlanks
MeshContentProviderAssetID, Cache, LRUCache, MeshData, ToMeshData
MeshDataFaceEnd, FaceStart, VertexEnd, VertexStart
MeshPartMeshId, Texture
MiscAdornee, AnimationId, StringLength, Value
ModelPrimaryPart, Scale
ModuleScriptByteCode, GUID, Hash, IsCoreScript
MouseServiceInputObject, InputObject2, MousePosition, SensitivityPointer
ParticleEmitterAcceleration, Brightness, Drag, Lifetime, LightEmission, LightInfluence, Rate, RotSpeed, Rotation, Speed, SpreadAngle, Texture, TimeScale, VelocityInheritance, ZOffset
PlayerAccountAge, CameraMode, DisplayName, HealthDisplayDistance, LocalPlayer, LocaleId, MaxZoomDistance, MinZoomDistance, ModelInstance, Mouse, NameDisplayDistance, Team, TeamColor, UserId
PlayerConfigurerPointer
PlayerMouseIcon, Workspace
PrimitiveAssemblyAngularVelocity, AssemblyLinearVelocity, Flags, Material, Owner, Position, Rotation, Size, Validate
PrimitiveFlagsAnchored, CanCollide, CanQuery, CanTouch
ProximityPromptActionText, Enabled, GamepadKeyCode, HoldDuration, KeyCode, MaxActivationDistance, ObjectText, RequiresLineOfSight
RenderJobFakeDataModel, RealDataModel, RenderView
RenderViewDeviceD3D11, LightingValid, SkyValid, VisualEngine
RunServiceHeartbeatFPS, HeartbeatTask
ScriptByteCode, GUID, Hash
ScriptContextRequireBypass
SeatOccupant
SkyMoonAngularSize, MoonTextureId, SkyboxBk, SkyboxDn, SkyboxFt, SkyboxLf, SkyboxOrientation, SkyboxRt, SkyboxUp, StarCount, SunAngularSize, SunTextureId
SoundIsPlaying, Looped, PlaybackSpeed, RollOffMaxDistance, RollOffMinDistance, SoundGroup, SoundId, Volume
SpawnLocationAllowTeamChangeOnTouch, Enabled, ForcefieldDuration, Neutral, TeamColor
SpecialMeshMeshId, Scale
StatsItemValue
SunRaysEffectEnabled, Intensity, Spread
SurfaceAppearanceAlphaMode, Color, ColorMap, EmissiveMaskContent, EmissiveStrength, EmissiveTint, MetalnessMap, NormalMap, RoughnessMap
TaskSchedulerRenderJobToRenderView, JobEnd, JobName, JobStart, MaxFPS, Pointer
TeamBrickColor
TerrainGrassLength, MaterialColors, WaterColor, WaterReflectance, WaterTransparency, WaterWaveSize, WaterWaveSpeed
TexturesDecal_Texture, Texture_Texture
ToolCanBeDropped, Enabled, Grip, ManualActivationOnly, RequiresHandle, TextureId, Tooltip
UnionOperationAssetId
UserInputServiceWindowInputState
VehicleSeatMaxSpeed, SteerFloat, ThrottleFloat, Torque, TurnSpeed
VisualEngineDimensions, FakeDataModel, Pointer, RenderView, ViewMatrix
WeldPart0, Part1
WeldConstraintPart0, Part1
WindowInputStateCapsLock, CurrentTextBox
WorkspaceCurrentCamera, DistributedGameTime, ReadOnlyGravity, World
WorldAirProperties, FallenPartsDestroyHeight, Gravity, Primitives, worldStepsPerSec
394 offsets in 68 namespaces. Example: gurp.get_offset("Humanoid", "Walkspeed").

Roblox-style Layer

compat

gurp loads a small Roblox/executor-style environment into every script. Many UI libraries and scripts written for other executors run without changes, for example SevereLib (the library gurphub.lua uses).

Not the real Roblox API

  • These are lightweight stand-ins, not real instances. game.Players.LocalPlayer is just { Name = "LocalPlayer" }, and unknown services return an empty object.
  • To read the actual game, use gurp.sdk.

Color3, Vector2, Enum

compat

Color3

MemberNotes
Color3.new(r, g, b)0–1 channels. Fields R, G, B (and lowercase r, g, b).
Color3.fromRGB(r, g, b)0–255 channels.
Color3.fromHSV(h, s, v)0–1 each.
c:ToHSV()Returns h, s, v.
c:Lerp(other, alpha)Blend toward other.

Vector2

MemberNotes
Vector2.new(x, y)Fields X, Y (and x, y).
+ - * /With another Vector2 (per component) or a number.
Vector2.zero, Vector2.one

Enum.KeyCode

Each entry is { Name = "E", Value = 0x45 }, where Value is the Windows key code (usable with gurp.is_key_down). Available names:

  • Letters A–Z, Number0–Number9, Keypad0–Keypad9, KeypadDot, F1–F12
  • LeftShift, RightShift, LeftControl, RightControl, LeftAlt, RightAlt
  • Space, Return/Enter/KeypadEnter, Escape, Backspace, Tab, Slash, Period, Minus, Equals
  • Left, Right, Up, Down, Insert, Delete, Home, End

game & Services

compat

MemberNotes
game:GetService("RunService")RenderStepped, Heartbeat, Stepped and Render all share one signal. :Connect(fn) runs fn every frame (about 60 fps) and returns a connection with :Disconnect().
game:GetService("UserInputService"):IsKeyDown(Enum.KeyCode.X or "X"), :GetMouseLocation() → Vector2, :GetKeysPressed() → { {KeyCode, Name} }.
game:GetService("HttpService"):JSONEncode(table), :JSONDecode(string) (returns nil on bad JSON).
game:GetService("Players")Placeholder only: { LocalPlayer = { Name = "LocalPlayer" } }.
game:HttpGet(url)Same as gurp.http_get.
game.PlaceIdAlways 0.
workspace.CurrentCamera.ViewportSizeVector2 of the screen size, updated every frame while a RunService callback is connected.
While at least one RunService connection is active, the script keeps running after your code reaches its end, until everything is disconnected or the environment is reset.

Example

local RunService = game:GetService("RunService")
local UIS = game:GetService("UserInputService")
local label = Drawing.new("Text")
label.Size = 16
label.Color = Color3.fromRGB(150, 220, 100)

local conn
conn = RunService.RenderStepped:Connect(function()
  local m = UIS:GetMouseLocation()
  label.Position = m + Vector2.new(12, 12)
  label.Text = UIS:IsKeyDown(Enum.KeyCode.LeftShift) and "shift!" or "hold shift"
  if UIS:IsKeyDown("End") then
    label:Remove()
    conn:Disconnect()
  end
end)

Drawing & task

compat

Drawing.new(class)

Classes "Square", "Text" and "Circle" are drawn; other class names make an object that doesn't draw. Objects are drawn every frame while a RunService callback is connected.

PropertyUsed byDefault
Visiblealltrue
Position (Vector2)all0, 0
Color (Color3)allwhite
Transparencyall, as opacity (1 = solid, 0 = invisible)1
ZIndexall, draw order0
SizeSquare: Vector2 · Text: font size0,0 · 13
Filled, Thickness, RoundingSquaretrue, 1, 0
Text, CenterText"", false
TextBounds (read only)Text: estimated size
RadiusCircle (always filled), pixels0, so set it

obj:Remove() deletes one object; Drawing.clear() deletes them all.

DrawingImmediate

One-frame shapes; call them inside a RunService callback.

DrawingImmediate.FilledRectangle(pos, size, color, opacity)
DrawingImmediate.FilledCircle(pos, radius, color, opacity)
DrawingImmediate.Line(from, to, color, opacity, thickness)

task

FunctionNotes
task.spawn(fn, ...)Runs fn as a coroutine on the next frame.
task.delay(seconds, fn, ...)Runs fn after seconds.
task.wait(seconds)Inside a spawned task, yields that task; outside, same as gurp.wait.
Spawned tasks only run while at least one RunService connection is active, because they're resumed by the same frame loop.

Global helpers

compat

Files (same sandbox folder as gurp.fs_*)

FunctionSame as
readfile(path)gurp.fs_read
writefile(path, data)gurp.fs_write
isfile(path)gurp.fs_exists
isfolder(path)gurp.fs_isdir
makefolder(path)gurp.fs_mkdir
delfile(path)gurp.fs_delete
listfiles(path)gurp.fs_list

Input

FunctionNotes
getpressedkey()The one key being typed, as an Enum.KeyCode name (e.g. "A", "Enter"), or "None". The most recently pressed key wins; Shift/Ctrl/Alt are only reported when held alone. Made for text boxes.
getpressedkeys()Names of every key held.
isleftpressed()Left mouse button held.
isrbxactive()Always true.

Language helpers

FunctionNotes
typeof(v)Like type, but returns "Color3", "Vector2", "Square", etc. for the layer's objects.
tick()Seconds (os.clock).
warn(...)Logs to the console like gurp.log.
math.clamp(v, lo, hi), math.round(n), math.sign(n)Roblox-style math helpers.

Loops & Rendering

guide

Style 1: a while loop

while true do
  gurp.draw.clear()
  -- read the game, queue drawings
  gurp.wait(0)   -- shows them
end
  • Simplest option; good for gurp.draw and gurp.ui.
  • gurp.wait(0) runs about once per frame. Use a bigger wait (0.1–1 s) for work that doesn't need to be smooth, like scanning folders.

Style 2: RunService callbacks

game:GetService("RunService").RenderStepped:Connect(function()
  -- runs every frame
end)
  • Needed for Drawing.new, DrawingImmediate and task.
  • Don't call gurp.wait inside a callback; use task.spawn + task.wait for delays.
Don't mix gurp.draw with Drawing.new in one script: the Drawing layer clears gurp.draw's list every frame.

Stopping cleanly

A reset raises "Lua environment reset" from gurp.wait. If you need to clean up first, wrap the loop:

local ok, err = pcall(function()
  while true do
    -- work
    gurp.wait(0)
  end
end)
gurp.set_desync(false)          -- example clean-up
if not ok and not tostring(err):find("environment reset") then error(err) end

Reading Players

guideexample

Name tags with health and distance

local health_off = gurp.get_offset("Humanoid", "Health")
local max_health_off = gurp.get_offset("Humanoid", "MaxHealth")

local function valid(x) return x and x ~= 0 end

while true do
  gurp.draw.clear()
  local me = gurp.get_localplayer()
  local cam = gurp.sdk.camera_position(gurp.get_camera())
  for _, plr in ipairs(gurp.sdk.children(gurp.sdk.players_service() or 0)) do
    local character = plr ~= me and gurp.sdk.character(plr)
    local head = valid(character) and gurp.sdk.find_child(character, "Head")
    local hum = valid(character) and gurp.sdk.find_child_of_class(character, "Humanoid")
    if valid(head) and valid(hum) and cam then
      local p = gurp.sdk.position(head)
      local s = gurp.draw.world_to_screen(p.x, p.y + 1.5, p.z)
      if s then
        local hp = gurp.memory.read_f32(hum + health_off) or 0
        local max = gurp.memory.read_f32(hum + max_health_off) or 100
        local dist = math.sqrt((p.x - cam.x)^2 + (p.y - cam.y)^2 + (p.z - cam.z)^2)
        local t = math.clamp(hp / math.max(max, 1), 0, 1)
        gurp.draw.text(s.x, s.y, ("%s  %dm"):format(gurp.sdk.display_name(plr), math.floor(dist)), 1, 1, 1, 1, true, 14)
        gurp.draw.rect(s.x - 20, s.y + 16, 40, 3, 0, 0, 0, 0.7)
        gurp.draw.rect(s.x - 20, s.y + 16, 40 * t, 3, 1 - t, t, 0.2, 1)
      end
    end
  end
  gurp.wait(0)
end
If a game uses its own character system and this finds nothing, collect the characters yourself and hand them to gurp with gurp.cache.

Attribute Cookbook

guideattributes

1. Find out what's there

for _, a in ipairs(gurp.sdk.attribute_values(obj, 128) or {}) do
  print(a.name, "f64=" .. a.f64, "f32=" .. a.f32, "u32=" .. a.u32, "bool=" .. tostring(a.bool))
end

Roblox number attributes are usually doubles, so read f64 for numbers and bool for booleans.

2. Read

local ammo = gurp.sdk.attribute_f32(gun, "Ammo", 0)     -- fallback if missing
local auto = gurp.sdk.attribute_bool(gun, "Automatic", false)

3. Write with an exact name

-- 4th argument false = exact match. The default (true) also matches "MaxAmmo".
if not gurp.sdk.attribute_set_f32(gun, "Ammo", 30, false) then
  warn("Ammo attribute not found")
end

4. Case-insensitive fallback

local function set_attr(obj, name, value)
  if gurp.sdk.attribute_set_f32(obj, name, value, false) then return true end
  for _, a in ipairs(gurp.sdk.attribute_values(obj, 256) or {}) do
    if a.name:lower() == name:lower() then
      return gurp.sdk.attribute_set_f32(obj, a.name, value, false)
    end
  end
  return false
end
Attributes vs Value objects: IntValue/BoolValue/ObjectValue children are instances, not attributes. Use value_*/set_value_* for those.
A value reading back changed doesn't mean the game uses it: many games re-sync values from the server. Check the effect in game, not just the readback.

Troubleshooting

help

ProblemLikely cause
Got nilThe address you passed was invalid or stale, or world_to_screen was given a point behind the camera.
Got 0The lookup worked but found nothing (no child with that name, player has no character yet).
Drawings don't appearThe script never calls gurp.wait/gurp.sleep_ms, or you're mixing gurp.draw with Drawing.new.
Drawings flicker or pile upMissing gurp.draw.clear() at the start of each frame.
script instruction limitA loop runs too long without waiting. Add gurp.wait inside it.
Lua environment resetThe environment was reset from the Lua tab. Expected; the script stops.
http_get errorsBad URL, no connection, or a response over 2 MB. Wrap it in pcall.
File functions return false/nilThe path has .. or a drive letter, or is over 240 characters. Paths are relative to %APPDATA%\gurproblox\ui-configs.
Values were fine, then brokeA respawn or server hop freed the objects. Look them up again each loop instead of caching them for long.
A write doesn't stickThe game overwrites it each frame or from the server. For part rotation use sdk.set_rotation; otherwise write in your loop.