for i,v in pairs(T) do
local newpivot = CFrame.new(pivot)
local offset = newpivot:toObjectSpace(v.CFrame)
newpivot = newpivot * CFrame.Angles(0, math.rad(10), 0)
v.CFrame = newpivot * offset -- Re-offset the part from the new rotation
end

Right now I’m using this cool formula (above) I found in devforum. The problem with this is it rotates based on angles.

But I want it to pivot to a vector3 direction. use case? Im allowing players to make custom bullet paths, when they shoot I need to rotate the sequence points they made with there path in the direction of the gun barrel using GunBarrel.Front.CFrame.LookVector

local function rotate(pivotTargetDir, originalPoints, pointParts)
local pivot = originalPoints[1]
local pivotRotationCf = CFrame.new(pivot, pivot+pivotTargetDir)
for i = 2, #originalPoints do
local originalPoint = originalPoints[i]
local posOffset = originalPoint-pivot
posOffset = Vector3.new(posOffset.X, posOffset.Y, -posOffset.Z)
local newPoint = pivotRotationCf*posOffset
pointParts[i].Position = newPoint
end
end

Here’s some code I used to test it on a baseplate.

local Players = game:getService("Players")
local RunService = game:GetService("RunService")
local startPositions = {
Vector3.new(7, 0, 5),
Vector3.new(4, 0, 10),
Vector3.new(7, 0, 12),
Vector3.new(13, 0, 16),
Vector3.new(8, 0, 21)
}
local plr = Players.LocalPlayer
local mouse = plr:GetMouse()
local pointParts = {}
local pointPartFolder = Instance.new("Folder")
pointPartFolder.Parent = workspace
local function createPointPart(num, pos, parent)
local part = Instance.new("Part")
part.Name = "P"..num
part.Color = Color3.new(1, 1, 1)
part.Material = Enum.Material.SmoothPlastic
part.Shape = Enum.PartType.Ball
part.Anchored = true
part.Size = Vector3.new(1, 1, 1)
part.Position = pos
part.Parent = parent
return part
end
local function createPointParts(positions, parent)
for i, v in ipairs(positions) do
pointParts[i] = createPointPart(i, v, parent)
end
end
createPointParts(startPositions, pointPartFolder)
local pivot = startPositions[1]
RunService.RenderStepped:Connect(function()
rotate(mouse.Hit.Position-pivot, startPositions, pointParts)
end)

can you guess what this is? is it welding, oh no it isn’t it’s custom welding, using pivot poin vector rotations lol.

This will be very useful for my path making system. Thank you so much! Would you mind if you could explain a bit of the math, this part:

for i = 1, #originalPoints do
local originalPoint = originalPoints[i]
local posOffset = originalPoint-pivot
posOffset = Vector3.new(posOffset.X, posOffset.Y, -posOffset.Z)
local newPoint = pivotRotationCf*posOffset
pointParts[i].Position = newPoint
end

Also I realised that I didn’t actually need to pivot around the first sequence point of the path, and instead pivot around the root, without your visual example I wouldn’t have realized this so thanks for that to. So now I pivot around the Root instead of the first sequence of the path.

Well, here’s some math explanation. posOffset is the offset in worldspace (relative to origin CFrame) between the pivot and another point. The calculations always use the same point coordinates to calculate the offset, instead of using the positions of the point parts. This means that the offsets used in the calculations are always the same.

The new calculated point, which is then set as the position of a point part, has to be offsetted based on a spesific direction. This can be achieved by CFrame calculations.

The functions creates a CFrame (pivotRotationCf) which’s LookVector points in the direction given to the function. Then it uses the offset that was calculated earlier to calculate the new point so that its offset relative to the new CFrame is the same as the offset of the corresponding original point relative to the origin CFrame. This calculation is done by multiplying the new CFrame with the offset, because multiplying a CFrame with a Vector3 gives a world space position that, when turned into object space of the CFrame, would be equal to the Vector3 in the multiplication. (The position of the original point relative to origin CFrame would be the same as the result of the calculation below, however, there is no reason to multiply the origin CFrame with a Vector, because you’ll just get that same Vector. But maybe this can help understand why I calculate the new point by multiplying the new CFrame with the offset.)

-- the result of this calculation is equal to posOffset
CFrame.new()*posOffset
-- the result of this calculation is equal to posOffset too.
CFrame.new():PointToObjectSpace(CFrame.new()*posOffset)
-- and so is the result of this
pivotRotationCf:PointToObjectSpace(pivotRotationCf*posOffset)

The reason why posOffset’s Z is turned into its opposite is because the negative Z direction is the forward direction of a CFrame. This isn’t really necessary to do in the function as the correct direction could be properly calculated outside the function instead.