Most players hate falling behind in Grapple People Simulator! script updates, but you can easily skip the boring parts.
You spend your time using your grappling hook to grab other players and drag them around the map for fun. Clicking lets you drop the rope whenever you want, and you can press F to ragdoll or T to change your camera view.
If you want to spice up your map exploration right now, here is the working script you need.
Grapple People Simulator! Script – Christmas Decoration & More
-- made by eazy
local ID = "129703286296659"
local NAME_HINT = "Christmas"
local PLACE_AT = nil
local MAP_TIMEOUT = 30
local GROUND_QUERYABLE = true
local DEFAULT_WALK_THRU = false
local PROMPT_TIMEOUT = 120
local MIN_COLLIDE_SIZE = 0
local SELF_TEST = true
local CLICK_SUSPEND = true
local SUSPEND_TIME = 0.016
local RS = game:GetService("ReplicatedStorage")
local IS = game:GetService("InsertService")
local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local function log(...) print("[Decor]", ...) end
local function bad(...) warn("[Decor]", ...) end
local SAVE_FILE = "venice_decor_collision.txt"
local function isSnowCloud(part)
return part:IsA("BasePart") and part.Name == "Snow cloud"
end
local function forceSnowCloud(part)
part.CanCollide = false
part.CanTouch = false
part.CanQuery = false
end
local function loadSaved()
if typeof(readfile) ~= "function" then return nil end
local ok, data = pcall(readfile, SAVE_FILE)
if not ok or not data then return nil end
data = data:gsub("%s+", "")
if data == "walk" then return true end
if data == "solid" then return false end
return nil
end
local function saveChoice(walk)
if typeof(writefile) ~= "function" then return end
pcall(writefile, SAVE_FILE, walk and "walk" or "solid")
end
local function promptWalkThrough(defaultWalk)
if _G.__DecorCollisionChosen ~= nil then
log("collision already answered this session:", _G.__DecorCollisionChosen and "walk-through" or "collidable")
return _G.__DecorCollisionChosen
end
local player = game:GetService("Players").LocalPlayer
local pg = player:FindFirstChild("PlayerGui") or player:WaitForChild("PlayerGui")
local walk = defaultWalk
local done = false
local gui = Instance.new("ScreenGui")
gui.Name = "DecorCollisionPrompt"
gui.ResetOnSpawn = false
gui.IgnoreGuiInset = true
gui.DisplayOrder = 999
gui.Parent = pg
local frame = Instance.new("Frame")
frame.AnchorPoint = Vector2.new(0.5, 0.5)
frame.Position = UDim2.fromScale(0.5, 0.5)
frame.Size = UDim2.fromOffset(340, 190)
frame.BackgroundColor3 = Color3.fromRGB(24, 26, 30)
frame.BorderSizePixel = 0
frame.Parent = gui
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 10)
corner.Parent = frame
local stroke = Instance.new("UIStroke")
stroke.Color = Color3.fromRGB(60, 66, 74)
stroke.Parent = frame
local title = Instance.new("TextLabel")
title.Size = UDim2.new(1, -24, 0, 30)
title.Position = UDim2.fromOffset(12, 12)
title.BackgroundTransparency = 1
title.Font = Enum.Font.GothamBold
title.TextSize = 17
title.TextXAlignment = Enum.TextXAlignment.Left
title.TextColor3 = Color3.fromRGB(240, 242, 245)
title.Text = "Christmas Decor"
title.Parent = frame
local note = Instance.new("TextLabel")
note.Size = UDim2.new(1, -24, 0, 32)
note.Position = UDim2.fromOffset(12, 42)
note.BackgroundTransparency = 1
note.Font = Enum.Font.Gotham
note.TextSize = 13
note.TextWrapped = true
note.TextXAlignment = Enum.TextXAlignment.Left
note.TextColor3 = Color3.fromRGB(160, 168, 178)
note.Text = "Should the decor block your movement? The snow baseplate is solid either way. Close applies the choice."
note.Parent = frame
local function makeOption(text, pos)
local b = Instance.new("TextButton")
b.Position = pos
b.Size = UDim2.new(0.5, -18, 0, 40)
b.BackgroundColor3 = Color3.fromRGB(40, 44, 50)
b.BorderSizePixel = 0
b.AutoButtonColor = false
b.Font = Enum.Font.GothamMedium
b.TextSize = 14
b.TextColor3 = Color3.fromRGB(190, 196, 204)
b.Text = text
b.Parent = frame
local c = Instance.new("UICorner")
c.CornerRadius = UDim.new(0, 6)
c.Parent = b
local s = Instance.new("UIStroke")
s.Color = Color3.fromRGB(70, 76, 84)
s.Parent = b
return b, s
end
local btnSolid, strokeSolid = makeOption("Collidable", UDim2.fromOffset(12, 88))
local btnWalk, strokeWalk = makeOption("Walk-through", UDim2.new(0.5, 6, 0, 88))
local function refresh()
local function style(btn, s, active)
btn.BackgroundColor3 = active and Color3.fromRGB(58, 110, 200) or Color3.fromRGB(40, 44, 50)
btn.TextColor3 = active and Color3.fromRGB(255, 255, 255) or Color3.fromRGB(190, 196, 204)
s.Color = active and Color3.fromRGB(90, 150, 245) or Color3.fromRGB(70, 76, 84)
end
style(btnSolid, strokeSolid, not walk)
style(btnWalk, strokeWalk, walk)
end
btnSolid.MouseButton1Click:Connect(function() walk = false refresh() end)
btnWalk.MouseButton1Click:Connect(function() walk = true refresh() end)
local close = Instance.new("TextButton")
close.Position = UDim2.fromOffset(12, 138)
close.Size = UDim2.new(1, -24, 0, 38)
close.BackgroundColor3 = Color3.fromRGB(235, 238, 242)
close.BorderSizePixel = 0
close.AutoButtonColor = false
close.Font = Enum.Font.GothamBold
close.TextSize = 14
close.TextColor3 = Color3.fromRGB(20, 22, 26)
close.Text = "Close"
close.Parent = frame
local cc = Instance.new("UICorner")
cc.CornerRadius = UDim.new(0, 6)
cc.Parent = close
close.MouseButton1Click:Connect(function() done = true end)
refresh()
local deadline = os.clock() + PROMPT_TIMEOUT
while not done and os.clock() < deadline do task.wait(0.05) end
_G.__DecorCollisionChosen = walk
saveChoice(walk)
gui:Destroy()
log("collision set to", walk and "walk-through" or "collidable", done and "" or "(timed out)")
return walk
end
local walkThrough = promptWalkThrough(loadSaved() or DEFAULT_WALK_THRU)
local map = workspace:FindFirstChild("Map")
if not map then
local t = os.clock() + MAP_TIMEOUT
while not map and os.clock() < t do map = workspace:FindFirstChild("Map") task.wait(0.25) end
end
if not map then bad("no Map — using workspace") map = workspace end
local decor = map:FindFirstChild("ChristmasDecor")
if decor then
log("decor already under", map:GetFullName(), "— reusing")
else
local function bestIn(container)
local best, bestScore = nil, 0
local function consider(inst)
if not (inst:IsA("Model") or inst:IsA("Folder")) then return end
local parts = 0
for _, d in ipairs(inst:GetDescendants()) do
if d:IsA("BasePart") then parts += 1 end
end
if parts == 0 then return end
local score = parts
if inst.Name:find(NAME_HINT) then score += 1000 end
if inst.Name == "ChristmasDecor" then score += 5000 end
if score > bestScore then best, bestScore = inst, score end
end
consider(container)
for _, d in ipairs(container:GetDescendants()) do consider(d) end
return best
end
local template, via
local asset = RS:FindFirstChild("ChristmasDecorAsset_" .. ID)
if asset then template, via = bestIn(asset), "ReplicatedStorage" end
if not template then
local ok, objs = pcall(function() return game:GetObjects("rbxassetid://" .. ID) end)
if ok and objs then
for _, o in ipairs(objs) do
template = bestIn(o)
if template then via = "GetObjects" break end
end
else
bad("GetObjects:", objs)
end
end
if not template then
local ok, container = pcall(function() return IS:LoadAsset(tonumber(ID)) end)
if ok and container then
template = bestIn(container)
via = template and "InsertService" or nil
else
bad("LoadAsset:", container)
end
end
if not template then
error("[Decor] no usable model — wrong ID, asset not public, or not published as a Model")
end
log("resolved via", via, "->", template:GetFullName(), template.ClassName)
decor = template:Clone()
decor.Name = "ChristmasDecor"
decor.Parent = map
if PLACE_AT then
local ok = pcall(function() decor:PivotTo(PLACE_AT) end)
if not ok then bad("decor is a", decor.ClassName, "— PivotTo unsupported, PLACE_AT ignored") end
end
local okPivot, pivot = pcall(function() return decor:GetPivot() end)
log("placed under", map:GetFullName(), "pivot", okPivot and tostring(pivot) or "n/a")
end
task.wait(0.5)
local function green(part)
if not part:IsA("BasePart") or part.Name ~= "Baseplate" then return false end
if part.Size.X < 30 or part.Size.Z < 30 then return false end
local c = part.Color
return part.Material == Enum.Material.Grass or (c.G > c.R * 1.08 and c.G > c.B * 1.08)
end
local function oldGround(c)
if green(c) then return true end
for _, d in ipairs(c:GetDescendants()) do if green(d) then return true end end
return false
end
for _, parent in ipairs({ map, workspace }) do
local old = parent:FindFirstChild("Baseplate")
if old and oldGround(old) then
old:Destroy()
log("removed old grass baseplate from", parent:GetFullName())
end
end
local groundFolder
for _, d in ipairs(decor:GetDescendants()) do
if d.Name == "Baseplate" and d:IsA("Folder") then groundFolder = d break end
end
if not groundFolder and decor.Name == "Baseplate" then groundFolder = decor end
local groundParts = {}
local isGround = {}
local function addGround(part)
if part:IsA("BasePart") and not isGround[part] then
isGround[part] = true
table.insert(groundParts, part)
end
end
if groundFolder then
for _, d in ipairs(groundFolder:GetDescendants()) do addGround(d) end
addGround(groundFolder)
log("baseplate folder:", groundFolder:GetFullName(), "->", #groundParts, "parts")
else
for _, d in ipairs(decor:GetDescendants()) do
if d:IsA("BasePart") and d.Name == "Baseplate" then addGround(d) end
end
if #groundParts > 0 then
bad("no Baseplate folder — fell back to", #groundParts, "loose part(s) named Baseplate")
else
bad("no Baseplate folder or part found — nothing will be solid under the decor")
end
end
local touched, solid, clouds = 0, 0, 0
local solidParts = {}
for _, d in ipairs(decor:GetDescendants()) do
if d:IsA("BasePart") and not isGround[d] then
d.CanQuery = false
d.CanTouch = false
if isSnowCloud(d) then
forceSnowCloud(d)
clouds += 1
elseif walkThrough then
d.CanCollide = false
else
local big = MIN_COLLIDE_SIZE <= 0
or (d.Size.X >= MIN_COLLIDE_SIZE and d.Size.Y >= MIN_COLLIDE_SIZE and d.Size.Z >= MIN_COLLIDE_SIZE)
d.CanCollide = big
if big then
solid += 1
table.insert(solidParts, d)
end
end
touched += 1
end
end
decor.DescendantAdded:Connect(function(d)
if isSnowCloud(d) and not isGround[d] then
forceSnowCloud(d)
end
end)
for _, g in ipairs(groundParts) do
g.CanCollide = true
g.CanTouch = false
g.CanQuery = GROUND_QUERYABLE
end
local suspended = false
local token = 0
local function restoreCollision()
suspended = false
for _, p in ipairs(solidParts) do
if p.Parent and not isSnowCloud(p) then
p.CanCollide = true
end
end
end
local function suspendCollision()
if walkThrough or #solidParts == 0 then return end
if not suspended then
suspended = true
for _, p in ipairs(solidParts) do
if p.Parent then p.CanCollide = false end
end
end
token += 1
local mine = token
task.delay(SUSPEND_TIME, function()
if mine ~= token then return end
if UIS:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) then
suspendCollision()
else
restoreCollision()
end
end)
end
if CLICK_SUSPEND and not walkThrough then
UIS.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
suspendCollision()
end
end)
RunService.PreRender:Connect(function()
if not suspended and UIS:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) then
suspendCollision()
end
end)
_G.__DecorSuspend = suspendCollision
log("click suspension armed —", SUSPEND_TIME .. "s window, baseplate exempt")
end
local stillQueryable, notSolid = 0, 0
for _, d in ipairs(decor:GetDescendants()) do
if d:IsA("BasePart") and not isGround[d] then
if d.CanQuery then stillQueryable += 1 end
if not walkThrough and not d.CanCollide then notSolid += 1 end
end
end
local groundUnsolid = 0
for _, g in ipairs(groundParts) do
if not g.CanCollide then groundUnsolid += 1 end
end
log(("pass done — %d parts click-through, %d solid, %d snow clouds uncollidable"):format(touched, solid, clouds))
log(("verify — %d decor parts still queryable, %d ground parts not solid"):format(stillQueryable, groundUnsolid))
if SELF_TEST then
local sample
for _, d in ipairs(decor:GetDescendants()) do
if d:IsA("BasePart") and not isGround[d] and d.Size.Y > 1 and not isSnowCloud(d) then sample = d break end
end
if sample then
local origin = sample.Position + Vector3.new(0, 40, 0)
local result = workspace:Raycast(origin, Vector3.new(0, -300, 0))
log("self-test down through", sample.Name, "->",
result and result.Instance:GetFullName() or "nothing")
if result and result.Instance == sample then
bad("ray still stops on the decor — CanQuery is being overridden")
end
end
endCopy the code above into a compatible Roblox script executor if you choose to test it.
Grapple People Simulator! Script Status
Roblox and game updates can affect compatibility, so the script’s status should be treated as temporary rather than guaranteed.
Frequently Asked Questions
What is a Grapple People Simulator! script?
A Grapple People Simulator! script is third-party Lua code intended to run alongside the Roblox game through a compatible script executor.
What features does this Grapple People Simulator! script include?
Different scripts contain different code. This version includes: Christmas Decoration.
How do you use the Grapple People Simulator! script?
Pick a compatible executor such as Hydrogen, MacSploit, AWP.GG, Delta, Fluxus, Codex, launch Roblox and join the game, copy the complete Lua code from the script card above, paste it into the executor’s editor, and click Run or Execute. Compatibility changes over time, so a name here doesn’t guarantee current support.
Can a Grapple People Simulator! script get your Roblox account banned?
Yes. Third-party scripts can violate Roblox rules and may put an account at risk. Only use code from a source you trust, never enter your Roblox password into a script or executor, and test on an alternate account first.
Does the Grapple People Simulator! script work on mobile?
Check whether both the executor and the script support your device and the current Roblox version. Mobile executor support does not guarantee that every script will work.