RopeConstraint appears in explorer, doesn't appear or work in game

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    This script (specifically the function GrappleSwing) creates a rope constraint that doesn’t appear in game but shows up in the explorer.
  2. What is the issue? Include screenshots / videos if possible!

recording of the issue:

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I rewrote the section of code that isn’t working, and I might use beams later if it still isn’t fixed

After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!

code (StarterCharacterScripts → SourceMovementFramework):

--# Variables
--/ Services
local run = game:GetService("RunService")
local plrs = game:GetService("Players")
local cas = game:GetService("ContextActionService")
local uis = game:GetService("UserInputService")
local rs = game:GetService("ReplicatedStorage")

--/ Folders
local modules = rs:WaitForChild("modules")
local storage = rs:WaitForChild("storage")

--// Player and Character
--/ Base
local player : Player = plrs.LocalPlayer
local char : Model = player.Character or player.CharacterAdded:Wait()

--/ Character Parts
local root : Part = char:WaitForChild("HumanoidRootPart") or char.PrimaryPart
local humanoid : Humanoid = char:WaitForChild("Humanoid")
local RArm : Part = char:WaitForChild("Right Arm")
local RightHandAttach : Attachment = RArm:WaitForChild("RightGripAttachment")

--// Movement Variables
--/ Momentum
local RunningMomentumGainFactor = 0.5 -- how fast the player will gain momentum
local MomentumLossFactor = 3
local MinumumMomentum, MaximumMomentum = 5, 35

--/ Grounded Check
local LegHeight = 3.005 -- ray distance for grounded check

--/ Jumping
local JumpCooldown = 0.5
local JumpUpwardsVelocity = 10
local isJumping = false

--/ Gear
-- Grappler
local GrapplerCursorPart = storage:WaitForChild("GrapplerCursorPart")
local GrapplerAttach = GrapplerCursorPart:WaitForChild("GrapplerAttach")
local GrapplerCursorUI = GrapplerCursorPart:WaitForChild("GrapplerCursor")
local GrapplerRange = 50
local canGrapple = false
local grappleHooked = false
local grapplerHookCooldown = 0.25

--# Default Keybinds
local DefaultKeybinds = {
	["Down Movement"] = Enum.KeyCode.LeftShift,
	["Up Movement"] = Enum.KeyCode.Space,
	["Dash"] = Enum.KeyCode.Q,
	["Core Gear"] = Enum.KeyCode.E,
	["Augment Gear"] = Enum.KeyCode.R
}
--// Math
local ceil = math.ceil
local pow = math.pow
local sqrt = math.sqrt
local clamp = math.clamp
local rad = math.rad
local deg = math.deg
local abs = math.abs
local sin = math.sin
local cos = math.cos
local inf = math.huge
local pi = math.pi
local rand = math.random

--# Functions
function momentum()
	if humanoid.MoveDirection == Vector3.new(0, 0, 0) then
		if humanoid.WalkSpeed > MinumumMomentum then
			humanoid.WalkSpeed -= MomentumLossFactor
		elseif humanoid.WalkSpeed < MinumumMomentum then
			humanoid.WalkSpeed = MinumumMomentum
		end
	else
		humanoid.WalkSpeed += RunningMomentumGainFactor

		if humanoid.WalkSpeed >= MaximumMomentum - 1 then
			humanoid.WalkSpeed = MaximumMomentum
		end
	end
end

function getVelocity()
	return root.AssemblyLinearVelocity
end

function isGrounded()
	-- param setup
	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = {char}
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude
	-- actual ray
	local raycastResult = workspace:Raycast(root.Position, Vector3.new(0, -(LegHeight), 0), raycastParams)
	
	if raycastResult ~= nil then
		return true
	else
		return false
	end
end

function SetGrapplerToMouse()
	local mouse = player:GetMouse()
	local hitPosition = mouse.Hit.Position
	if player:DistanceFromCharacter(hitPosition) <= GrapplerRange then
		GrapplerCursorPart.Position = hitPosition
		canGrapple = true
		GrapplerCursorUI.Enabled = true
	else
		GrapplerCursorPart.Position = Vector3.new(0, inf, 0)
		canGrapple = false
		GrapplerCursorUI.Enabled = false
	end
end

function GrappleHook(actionName, inputState, inputObj) -- yanking
	if inputState == Enum.UserInputState.Begin then
		print("hook")
		grappleHooked = true
		task.wait(grapplerHookCooldown)
		grappleHooked = false
	end
end

function GrappleSwing(actionName, inputState, inputObj) -- swinging
	if inputState == Enum.UserInputState.Begin then
		print("swing")
		grappleHooked = true
		local rope = Instance.new("RopeConstraint")
		rope.Thickness = 0.1
		rope.Name = "GrapplerRope"
		rope.Color = BrickColor.Black()
		rope.Length = GrapplerRange
		rope.Enabled = true
		rope.Attachment0 = GrapplerAttach
		rope.Attachment1 = RightHandAttach
		rope.Parent = RArm
		rope.Visible = true
	elseif inputState == Enum.UserInputState.End then
		print("swing release")
		grappleHooked = false
		if RArm:FindFirstChild("GrapplerRope") then
			RArm.GrapplerRope:Destroy()
		end
	end
end

function Grapple(actionName, inputState, inputObj) -- detect inputs
	local mouse = player:GetMouse()
	local hit = mouse.Hit
	local target : Part = mouse.Target
	if player:DistanceFromCharacter(hit.Position) <= GrapplerRange then
		if target:HasTag("swing") then
			GrappleSwing(actionName, inputState, inputObj)
		else
			GrappleHook(actionName, inputState, inputObj)
		end
	end
end

function GrapplerInit() -- initialize
	local cursorClone : Part = GrapplerCursorPart:Clone()
	cursorClone.Parent = workspace
	cursorClone.Name = cursorClone.Name .. player.Name
	GrapplerCursorPart = cursorClone
end

--// Start and Update (unity reference)

function Start()
	GrapplerInit()
end

function OnRenderStepped()
	-- Momentum
	momentum()
	-- Gear
	SetGrapplerToMouse()
end

function OnHeartBeat()
	
end

--# Connections, Bindings, and setup
Start()
run.RenderStepped:Connect(OnRenderStepped)
run.Heartbeat:Connect(OnHeartBeat)

cas:BindAction("Grappler", Grapple, false, DefaultKeybinds["Core Gear"])

I tried a beam, and even that doesn’t appear so i dont even know what is happening

apparently im just stupid, the rope was connecting to something inside the character so i couldn’t see it, fixed the problem by changing a bunch of stuff