Skip to main content

Instance Manipulation

Every object in the Roblox world is an Instance. Understanding which properties you can read, which you can change, and what effect those changes have is fundamental to scripting.

Reading Properties

Any property visible in Dex can be read:

local part = workspace:FindFirstChild("SomePart")
print(part.Position) -- Vector3
print(part.Size) -- Vector3
print(part.CFrame) -- CFrame (position + rotation combined)
print(part.Transparency) -- 0-1
print(part.Color) -- Color3
print(part.Anchored) -- boolean
print(part.CanCollide) -- boolean
print(part.Material) -- Enum.Material

Client-Side vs Server-Side Changes

Client-side only (only you see it):

  • Part position/CFrame changes
  • Part color, transparency changes
  • Humanoid.WalkSpeed, JumpPower
  • Camera properties
  • GUI visibility

Affects server (only via remotes):

  • Anything that changes game state for everyone
  • NPC health, player currency, inventory

If you change humanoid.WalkSpeed = 100 on your character, you move faster on your screen. But the server may desync your position and teleport you back, or kick you for speed violations.

Position and Movement

local hrp = Players.LocalPlayer.Character:WaitForChild("HumanoidRootPart")

-- Teleport to a position
hrp.CFrame = CFrame.new(0, 100, 0)

-- Teleport to another player
local target = Players:FindFirstChild("TargetName")
if target and target.Character then
hrp.CFrame = target.Character.HumanoidRootPart.CFrame + Vector3.new(0, 5, 0)
end

-- Move relative to current position
hrp.CFrame = hrp.CFrame + Vector3.new(10, 0, 0) -- move 10 studs on X axis

-- Face a direction
local targetPos = Vector3.new(100, 0, 100)
hrp.CFrame = CFrame.lookAt(hrp.Position, targetPos)

Teleporting is client-side. Roblox replication will move your visible position, but server-side physics may fight you. Teleporting too far at once often causes a "sanity teleport" back.

CFrame Basics

CFrame (CoordinateFrame) combines position and rotation:

-- Create from position
local cf = CFrame.new(10, 5, 20)

-- Create from position + direction
local cf = CFrame.lookAt(Vector3.new(0,0,0), Vector3.new(1,0,0)) -- look at X+

-- Create from Euler angles (in radians)
local cf = CFrame.Angles(math.rad(90), 0, 0) -- 90 degree pitch

-- Combine: multiply CFrames
local cf = CFrame.new(0, 0, 0) * CFrame.Angles(0, math.rad(45), 0)

-- Extract position and rotation
local pos = cf.Position -- Vector3
local rx, ry, rz = cf:ToEulerAnglesXYZ()

-- Move forward by 5 studs (relative to current rotation)
hrp.CFrame = hrp.CFrame * CFrame.new(0, 0, -5) -- forward in Roblox is -Z

Part Properties

local part = workspace.SomePart

-- Visibility
part.Transparency = 0.5 -- 0 = solid, 1 = invisible
part.Color = Color3.fromRGB(255, 0, 0) -- red
part.Material = Enum.Material.Neon -- glowing material

-- Physics
part.Anchored = true -- can't move (stops physics)
part.CanCollide = false -- no collision
part.Massless = true -- no physics weight

-- Size and shape
part.Size = Vector3.new(4, 4, 4)

Modifying Another Player's Character

You can read other players' characters, and make client-side changes:

local target = Players:FindFirstChild("SomePlayer")
if target and target.Character then
local theirHumanoid = target.Character:FindFirstChildOfClass("Humanoid")
local theirHRP = target.Character:FindFirstChild("HumanoidRootPart")

-- Read their state
print(theirHumanoid.Health, theirHumanoid.WalkSpeed)
print(theirHRP.Position)

-- Client-side only change (visual on your screen)
for _, part in target.Character:GetDescendants() do
if part:IsA("BasePart") then
part.Transparency = 0.5 -- make them semi-transparent (only you see this)
end
end
end

Destroying and Creating Instances

-- Destroy an instance (client-side)
local annoying = workspace:FindFirstChild("AnnoyngPart")
if annoying then annoying:Destroy() end

-- Create and parent a new instance
local highlight = Instance.new("Highlight")
highlight.FillColor = Color3.fromRGB(255, 0, 0)
highlight.OutlineColor = Color3.fromRGB(255, 255, 255)
highlight.Adornee = targetCharacter
highlight.Parent = game:GetService("CoreGui") -- parent to CoreGui so it persists

Detecting Property Changes

Subscribe to changes on any property:

local part = workspace.SomePart

-- GetPropertyChangedSignal: specific property
part:GetPropertyChangedSignal("CFrame"):Connect(function()
print("part moved to", part.Position)
end)

-- Changed: fires for any property change (use sparingly — noisy)
part.Changed:Connect(function(propertyName)
if propertyName == "Transparency" then
print("transparency changed to", part.Transparency)
end
end)

The AncestryChanged Pattern

Detect when an instance is removed from the tree:

local enemy = workspace.Enemies:FindFirstChild("Boss")
if enemy then
enemy.AncestryChanged:Connect(function(child, parent)
if parent == nil then
print("Boss was removed from the game")
end
end)
end

This is useful for tracking enemy deaths, round resets, and other lifecycle events.

ChildAdded / ChildRemoved

React to instances being added or removed from a folder:

local enemyFolder = workspace:WaitForChild("Enemies")

enemyFolder.ChildAdded:Connect(function(newEnemy)
print("New enemy spawned:", newEnemy.Name)
-- Set up ESP for this enemy
end)

enemyFolder.ChildRemoved:Connect(function(removedEnemy)
print("Enemy removed:", removedEnemy.Name)
-- Remove ESP for this enemy
end)

This pattern is how you build dynamic ESP that automatically handles new entities.