Grapple People Simulator! Script (November 2026)

PUBLISHEDUPDATED
1 Available ScriptFree

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

Christmas Decoration & MoreFree
Christmas Decoration
-- 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
end
Executor compatibility changes over time. Check current reports before testing.

Copy the code above into a compatible Roblox script executor if you choose to test it.

Grapple People Simulator! Script Status

✓AvailabilityFree
$Price$0
◫CompatibilityDesktop & Mobile
★SafetyVerified

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.

Check out our Roblox Scripts hub and Roblox Games Directory for more.

Leave a Comment