Localscript Not functioning properly

I am making a 2D “Platformer game” which requires the arm to follow the cursor.
Here’s my code:

local rs = game:GetService("ReplicatedStorage")
local plrs = game:GetService("Players")
local run = game:GetService("RunService")

local player = plrs.LocalPlayer
local mouse = player:GetMouse()

local function setupCharacter(character)

	local torso = character:WaitForChild("Torso")
	local rightArm = character:WaitForChild("Right Arm")

	local event = rs:WaitForChild("events"):WaitForChild("LightsaberMove")

	local armWeld = Instance.new("Weld")
	armWeld.Part0 = torso
	armWeld.Part1 = rightArm
	armWeld.Parent = rightArm

	local armOffset = torso.CFrame:Inverse() * rightArm.CFrame
	local rotCFrame
	local armPos

	run.RenderStepped:Connect(function()
		if not torso or not rightArm then return end
		local torsoPos = torso.Position
		local mouseHit = mouse.Hit.Position

		-- keep the x position of the mouse aligned with the torso
		mouseHit = Vector3.new(torsoPos.X, mouseHit.Y, mouseHit.Z)

		-- create a cframe that makes the torso look at the mouse
		local lookAtCFrame = CFrame.lookAt(torsoPos, mouseHit)
		rotCFrame = CFrame.new(torsoPos) * CFrame.Angles(lookAtCFrame:ToEulerAnglesXYZ())

		-- calculate the arm's position relative to the torso
		armPos = rightArm.CFrame.Position - torso.CFrame.Position

		-- update the weld with the new rotation
		armWeld.C0 = armOffset * torso.CFrame:toObjectSpace(rotCFrame)
	end)

	local function sendData()
		if rotCFrame and armPos then
			event:FireServer(rotCFrame, armPos, torso.CFrame)
		end
	end

	-- repeat
	while true do
		sendData()
		wait(0.05)
	end
end

-- setup character when the player spawns
setupCharacter(player.Character or player.CharacterAdded:Wait())

-- handle character respawn and setup
player.CharacterAdded:Connect(function(newCharacter)
	newCharacter:WaitForChild("Torso")
	newCharacter:WaitForChild("Right Arm")

	setupCharacter(newCharacter)
end)

The arm is not in the original RightArm position, instead it is in the torso of the player.
How can I fix this?

Change:

rotCFrame = CFrame.new(torsoPos) * CFrame.Angles(lookAtCFrame:ToEulerAnglesXYZ())
local armOffset = CFrame.new(1.5, 0.5, -0.5)
rotCFrame = 
	torso.CFrame * 
	armOffset * 
	CFrame.Angles(lookAtCFrame:ToEulerAnglesXYZ())

I’m not 100% the armOffset I gave is the right numbers. It should be clear what it does though.

I made the changes, and some stuff broke.

  1. The info sent to the server is a little funny and broken, I’m not sure why.
  2. when I change the direction faced, it’s inverted for some reason

Below is an older version of the script, which had the correct arm placement, but had a problem with respawning, which is fixed in the script on the original post.

local rs = game:GetService("ReplicatedStorage")
local plrs = game:GetService("Players")
local run = game:GetService("RunService")

local player = plrs.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local mouse = player:GetMouse()

local torso = char:WaitForChild("Torso")
local rightArm = char:WaitForChild("Right Arm")

local event = rs:WaitForChild("events"):WaitForChild("LightsaberMove")

local armOffset = torso.CFrame:Inverse() * rightArm.CFrame

-- weld to attach right arm to torso
local armWeld = Instance.new("Weld")
armWeld.Part0 = torso
armWeld.Part1 = rightArm
armWeld.Parent = rightArm

local rotCFrame -- store rotation data
local armPos -- store arm position relative to torso

-- update arm's position and rotation every frame
run.RenderStepped:Connect(function()
	local torsoPos = torso.Position
	local mouseHit = mouse.Hit.Position

	-- lock movement to y-z plane
	mouseHit = Vector3.new(torsoPos.X, mouseHit.Y, mouseHit.Z)

	-- calculate direction to mouse
	local lookAtCFrame = CFrame.lookAt(torsoPos, mouseHit)
	rotCFrame = CFrame.new(torsoPos) * CFrame.Angles(lookAtCFrame:ToEulerAnglesXYZ())

	-- store arm's relative position
	armPos = rightArm.CFrame.Position - torso.CFrame.Position

	-- update weld with new rotation
	armWeld.C0 = armOffset * torso.CFrame:toObjectSpace(rotCFrame)
end)

-- send rotation and position data to server
local function sendData()
	if rotCFrame and armPos then
		event:FireServer(rotCFrame, armPos, torso.CFrame)
	end
end

-- run continuously
while true do
	sendData()
	wait(0.05)
end

how can I set position and create a weld while being fast? since it keeps flying around and breaking