Syncing a anchored part's position & rotation to a unanchored part's position & rotation without welds

context
i’m trying to create a general visual effects system that relies on parts. i couldn’t find any general guidelines to follow on my own, so i just winged it. however, i’ve only just started and haven’t made the system yet. i did plan out how the system would work, so i’ll go through it so that you know my intentions with it & how it’d be used, hopefully.

i’ve decided on using parts that are Anchored all the time, with CanCollide, CanQuery and CanTouch as false. those parts would have their Color, Shape, Material, Size & CFrame to represent a visual effect. these parts would be in a object pool, where a effect structure would get parts from the pool as it starts, and then returns the parts back to it.

the effect structure would hold a start, runtime & end function, with the parts it’d be using in a table. it’s runtime function would be executed during every frame, which would update variables on the parts on the previously mentioned table. though, i’m not certain if i should use a Heartbeat or a Renderstepped event.

the object pool is mainly for memory consumption concerns, a lot of visual effects can happen at one time & they generally have a short lifespan, so it seemed wise to stick with it instead of instantiating parts and deleting them.

because of the effect structure, i don’t want to unanchor the part and then weld it for it to follow another part when the effect starts & then revert it back to being anchored and removing the weld, if the effect is ment to follow a part’s position & orientation. i see this method as the last resort option.

e: “is there any specific reason why you don’t want to use the weld method?”
some effects that i’m intending to use have can show up for a few RenderStepped/Heartbeat frames that may appear multiple times within a within a second. this could mean multiple welds being applied during those frames & then being detached in the same frame if it has a short lifetime or in the next few frames, so they end up being a concern for optimization’s sake.

setup
before actually building the system, i wanted to try if the plan actually works first. to be more specific, i wanted to see if tying functionality to either Heartbeat or Renderstepped would have a okay-ish result.

i made a tool for a quick test, when activated, would position a glowing white 2x4 part on a r6 character’s right arm via CFrame. i have tried both Heartbeat and Renderstepped. in those tests, i’d manually remove the Animate local script on the player character to be able to tell if the white part’s position or orientation is desynced from the right arm.

-hierarchy-

🔧 Tool
	📜 LocalScript
		🧱 Visual

-local script-

local Player = game.Players.LocalPlayer
local Character = nil
if Player.Character and Player.Character.Parent then
	Character = Player.Character
else
	Player.CharacterAdded:Wait()
end

local Tool = script.Parent
local Active = false

local function Start()
	Active = true
end
local function Stop()
	Active = false
	script.Visual.CFrame = CFrame.new(Vector3.new(0, math.huge, 0))
end

Tool.Activated:Connect(Start)
Tool.Deactivated:Connect(Stop)
Tool.Unequipped:Connect(Stop)

game["Run Service"].Heartbeat:Connect(function(DT:number)
	if Active then
		script.Visual.CFrame = Character["Right Arm"].CFrame
	end
end)

issue
procedure:

  • delete the “Animate” local script, in the player character to prevent the walking animation from working so that the part position & orientation desyncs are easier to tell
  • set the player character’s walkspeed to 10000
  • move around with WASD, check if there’s any positional desync with the part to the right arm when moving at high speeds
  • use MouseLockShift or 1st person view, rotate the player character quickly to check for any rotational desync

in my tests, only quick rotations causes the part to desync for both, seemingly at a pivot on the humanoid root part, which is what i want to solve. besides that, i can’t really tell much of a difference between the two:
Heartbeat

RenderStepped

please tell me you searched for answers for this problem
yes, i did. a few terms i used on the searchbar are:

attach anchored part to unanchored part #help-and-feedback:scripting-support
(closest thread was about connecting a player (character’s arm) to a anchored part, which is the reverse of my problem)
part camera jitter #help-and-feedback:scripting-support
(this was the closest thing i could think of to having a syncing problem, as camera stuff often uses Renderstepped, but i couldn’t find anything relevant to my problem)

after the 2nd search, i was clueless to what kind of keyword i should use, so i resorted to making a topic.

  1. Heartbeat: The Heartbeat event fires once per frame before the rendering occurs. It is a good choice when you need to perform calculations and updates that are not dependent on the rendering, such as physics calculations or AI logic.

  2. RenderStepped: The RenderStepped event fires once per frame after the rendering occurs. It is useful when you need to perform updates that are dependent on the rendering, such as updating the position or orientation of visual effects.

In your case, since you want to update the position of the visual effect parts based on the right arm’s position, using the RenderStepped event would be more appropriate. This ensures that the updates are synchronized with the rendering process and avoids any desync issues.

To implement the RenderStepped event in your code, you can replace the Heartbeat event with the RenderStepped event and modify the corresponding code as follows:

game["Run Service"].RenderStepped:Connect(function()
    if Active then
        script.Visual.CFrame = Character["Right Arm"].CFrame
    end
end)

this looks like a language model excerpt. looks like it didn’t get that i’ve already tried both Heartbeat and RenderStepped. i’ve already provided 2 videos showing the results in the first post, they show signs of mostly rotational desync pivoting from the character’s humanoid root part.

if you want to continue being the messager for it, try telling it something like “the desync still happens regardless of using Heartbeat or RenderStepped”.

it doesn’t look like i’ll get a working answer soon, so i’ll check if the last resort method involving welds works, in case there’s other people who are experiencing the same problem, but are open to using welds. if it does, i’ll post it here, but not mark it as a answer because it doesn’t fit this topic.

e: here it is. this works for both Welds and WeldConstraints, but i think the latter is more preferable. it’s important that the weld gets disabled first before anchoring so that the character doesn’t get dragged along with it when it’s super far away, unless you’re using a different method to hide the part (i.e, setting transparency to 0). i used the “teleport part super far away” method because it was mentioned that CFrame is “a fast property” to change.

local Player = game.Players.LocalPlayer
local Character = nil
if Player.Character and Player.Character.Parent then
	Character = Player.Character
else
	Player.CharacterAdded:Wait()
end

local Tool = script.Parent
local Active = false

local function Attach()
	script.Visual.Anchored = false
	script.Visual.CFrame = Character["Right Arm"].CFrame
	script.Visual.WeldConstraint.Part1 = Character["Right Arm"]
	script.Visual.WeldConstraint.Enabled = true
end
local function Detach()
	script.Visual.WeldConstraint.Enabled = false
	script.Visual.CFrame = CFrame.new(Vector3.new(0, math.huge, 0))
	script.Visual.Anchored = true
end

local function Start()
	Active = true
	Attach()
end
local function Stop()
	Active = false
	Detach()
end

Tool.Activated:Connect(Start)
Tool.Deactivated:Connect(Stop)
Tool.Unequipped:Connect(Stop)

game["Run Service"].RenderStepped:Connect(function(DT:number)
	if Active then
		script.Visual.CFrame = Character["Right Arm"].CFrame
	end
end)

e2: this should be the last edit unless i make another mistake and find out about it. i was rushing on the 1st edit, so i didn’t explain how it works, mostly.

before i get into it, i have to mention using CFrame or both Position and Orientation seem to have different behaviours. i made a test where a part stretches out from the character’s humanoid root part to a clicked position & attached that to the humanoid root part via a WeldConstraint, with the part adapting to the difference in distance and the movement of the humanoid root part by setting it’s position & rotation in a RenderStepped function. using CFrame, the character gets stuck or have glitchy camera-desyncing movement, because (i think) CFrame moves whatever’s connected to the part along with it. using Position & Orientation avoids the problem that occurs when using CFrame.

the script works by setting the part’s position & orientation via cframe, setting anchored to false, then attaching the weld to the part the moment the tool is activated, and doesn’t have to change the positioning & rotation of the part afterwards because it’s goal was to just sync the position & rotation relative to the character’s right arm. upon deactivation, the weld is detached by disabling it, the part is hidden by placing it far away (which helps in keeping it’s transparency property to whatever it was since the script isn’t hiding it by setting it to 1), and is finally anchored so that it doesn’t eventually fall to the void to prevent it from being deleted.

because of the traits mentioned eariler, if you want to change the position and/or orientation relative to the attached part in a RenderStepped function while a WeldConstraint is attached, set the part’s Position & Orientation property instead of using CFrame so that the part intended to be used as a visual effect is the only object moved by the script.